Untuk memastikan sheet SwiftUI kekal terbuka semasa kemas kini, kekalkan identiti hos pembentangannya dan pastikan binding pembentangannya kekal aktif. Lampirkan sheet pada bekas yang stabil supaya kandungan anak yang berubah boleh dikemas kini tanpa menggantikan pembentang.
Panduan ini ditujukan kepada pembangun yang membina app Mac dengan sheet boleh sunting yang sepatutnya kekal kelihatan semasa antara muka di bawahnya berubah. Contoh yang dibincangkan menggunakan teks setempat sintetik dan memisahkan tiga perkara yang boleh anda periksa secara berasingan: keadaan pembentangan, jangka hayat paparan pembentang dan kandungan editor.
Mengapakah kemas kini paparan boleh menyebabkan sheet hilang?
SwiftUI boleh mencipta nilai paparan baharu semasa menilai body sambil mengekalkan identiti paparan yang dipaparkan. Keadaan berterusan sepanjang jangka hayat identiti itu. Mengalih keluar paparan atau menukar identitinya menamatkan jangka hayat tersebut; pertukaran antara cabang bersyarat juga boleh mencipta identiti berbeza, walaupun kedua-dua cabang mengandungi jenis paparan yang sama. Apple menerangkan hubungan ini dalam Demystify SwiftUI.
Bagi sheet yang dikawal Boolean, kawalan pembentangan yang didokumenkan ialah binding yang dihantar kepada sheet(isPresented:onDismiss:content:): nilai true meminta pembentangan. Apabila menyiasat sheet yang hilang, periksa kedua-dua binding itu dan sama ada paparan yang membawa pengubah suai tersebut masih wujud. Nilai true yang disimpan di tempat lain tidak membuktikan bahawa hos pembentangan asal masih wujud. Lihat dokumentasi sheet Boolean Apple.
Punca yang lebih langsung ialah pengecam eksplisit yang berubah. Apple mendokumenkan bahawa menukar nilai yang diberikan kepada id(_:) menetapkan semula identiti paparan, termasuk keadaannya. Periksa paparan pembentang dan leluhurnya untuk pengecam yang diterbitkan daripada pembilang semakan, teks boleh sunting atau nilai yang baru dijana. Buang pengecam sedemikian jika tingkah laku tetapan semula itu tidak disengajakan. Lihat id(_:).
Kesimpulan praktikal daripada reka bentuk ini ialah meletakkan pengubah suai sheet di luar bahagian antara muka yang berubah. Jika paparan pemuatan, baris yang ditapis atau susun atur butiran alternatif boleh hilang, leluhur berterusan terdekat yang sesuai biasanya merupakan pemilik pembentangan yang lebih baik.
Bina pemilik sheet yang stabil dengan contoh Mac yang lengkap
Cipta app SwiftUI macOS dalam Xcode, tetapkan sasaran penggunaan kepada macOS 12 atau lebih baharu, dan gantikan deklarasi app serta paparan kandungan yang dijana dengan satu fail berikut. Kekalkan hanya satu deklarasi app @main. Asas macOS 12 membolehkan tindakan persekitaran dismiss dalam contoh ini; TextEditor sendiri tersedia mulai macOS 11. Lihat dokumentasi dismiss Apple dan dokumentasi TextEditor.
Paparan akar tetingkap memiliki bendera pembentangan, teks boleh sunting, pembilang semakan dan bendera susun atur. VStack luarnya membawa pengubah suai sheet. Hanya kandungan di dalam bekas itu bertukar cabang. Apple mengesyorkan supaya keadaan diisytiharkan secara peribadi pada paparan tertinggi yang memerlukannya dan binding dihantar kepada anak yang perlu mengubahnya. Lihat State.
import SwiftUI
@main
struct StableSheetDemoApp: App {
var body: some Scene {
WindowGroup {
SheetOwnerView()
}
}
}
struct SheetOwnerView: View {
@State private var isEditorPresented = false
@State private var note = "Sample note Alpha"
@State private var revision = 0
@State private var compactLayout = false
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Local Notes")
.font(.title)
if compactLayout {
Text("Compact summary: revision \(revision)")
} else {
VStack(alignment: .leading, spacing: 8) {
Text("Expanded summary")
Text("Revision \(revision)")
Text(note)
}
}
Button("Edit Note") {
isEditorPresented = true
}
}
.padding(24)
.frame(minWidth: 440, minHeight: 260)
.sheet(isPresented: $isEditorPresented) {
NoteEditorSheet(
note: $note,
revision: $revision,
compactLayout: $compactLayout
)
}
}
}
struct NoteEditorSheet: View {
@Binding var note: String
@Binding var revision: Int
@Binding var compactLayout: Bool
@Environment(\.dismiss) private var dismiss
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Edit Sample Note")
.font(.headline)
TextEditor(text: $note)
.frame(minHeight: 160)
Text("Owner revision: \(revision)")
Button("Update Owner") {
revision += 1
compactLayout.toggle()
}
HStack {
Spacer()
Button("Done") {
dismiss()
}
}
}
.padding(24)
.frame(width: 460, height: 340)
}
}
Ini ialah app demonstrasi lengkap yang diperiksa berdasarkan API yang didokumenkan. Ia tidak dikompil atau dijalankan di sini kerana persekitaran ini tidak mempunyai toolchain Swift atau masa jalan macOS.
Cara menguji kemas kini tanpa menutup sheet
- Jalankan app dan klik
Edit Note. - Gantikan teks contoh dengan
Sample note Beta. - Klik
Update Ownerbeberapa kali. Setiap klik menaikkan keadaan pemilik dan menukar kandungan bersyarat pemilik. - Sahkan bahawa editor kekal kelihatan, teksnya kekal
Sample note Betadan paparan semakannya meningkat. - Klik
Done. Sahkan bahawa tetingkap memaparkan teks yang telah disunting dalam susun atur dikembangkan apabila susun atur itu aktif. - Buka semula editor dan sahkan bahawa teks yang telah disunting masih tersedia.
Butang kemas kini berada di dalam sheet supaya ujian tidak bergantung pada klik tetingkap di bawahnya. AppKit mendokumenkan sheet sebagai modal dokumen: semasa sheet kelihatan, kebanyakan peristiwa yang ditujukan kepada tetingkap induknya dilarang. Mengemas kini pemilik melalui binding membolehkan contoh ini menguji perubahan keadaan secara langsung. Lihat beginSheet(_:completionHandler:).
Tentukan maksud tindakan menutup editor
Contoh ini mengedit teks pemilik dengan serta-merta. Done menutup editor; ia tidak menjalankan operasi simpan yang berasingan. Rentetan itu kekal dalam keadaan setempat tetingkap, dan contoh ini tidak menyediakan penyimpanan merentas pelancaran app. Tingkah laku itu mengikut reka bentuk binding bersama yang diterangkan dalam State.
Jika tugasan anda memerlukan draf yang boleh dibatalkan, gunakan nilai draf berasingan dan salin ke dokumen hanya selepas tindakan pengesahan yang jelas. Tentukan tingkah laku itu sebelum melaksanakan penutupan: memutuskan sama ada draf perlu digunakan atau dibuang berbeza daripada memutuskan paparan mana yang memiliki sheet.
Diagnosis penutupan dengan tiga pemeriksaan berasingan
Gunakan urutan berikut pada app anda. Urutan ini menukarkan peraturan identiti umum kepada penyiasatan terfokus, tanpa mengandaikan bahawa semua sheet yang hilang mempunyai punca yang sama.
| Pemeriksaan | Perkara yang perlu diperiksa | Pembetulan praktikal |
|---|---|---|
| Nilai pembentangan | Setiap penulisan yang menetapkan Boolean kepada false atau mengosongkan item pembentangan pilihan |
Kekalkan penulisan penutupan dalam tindakan tutup yang disengajakan |
| Identiti pembentang | Cabang bersyarat, baris yang dialih keluar, pengecam leluhur yang berubah | Alihkan keadaan pembentangan dan pengubah suai ke leluhur stabil yang sesuai |
| Jangka hayat kandungan | Keadaan setempat sheet, pengecam kandungan yang berubah, penyegerakan editor | Kekalkan sesi pengeditan yang dikehendaki dan kemas kini kandungan sedia ada dengan sengaja |
Mula-mula, cari tugasan pada sifat pembentangan dan panggilan kepada dismiss() dalam projek anda. Panggilan balik muat semula mungkin menutup sheet secara jelas. Baca dismiss di dalam paparan sheet itu sendiri, seperti yang dilakukan oleh contoh ini: Apple mendokumenkan bahawa tindakan itu terpakai pada persekitaran tempat ia diperoleh. Membacanya dalam paparan akar tetingkap mungkin menyasarkan tetingkap itu. Lihat dismiss.
Kedua, periksa hierarki di atas pengubah suai. Jika sheet dilampirkan pada paparan butiran yang dialih keluar semasa muat semula, alihkannya ke atas sempadan penggantian itu. Alihkan juga keadaan pembentangan yang dimilikinya secara setempat. Menyimpan bendera dalam anak yang identitinya tamat menyebabkan storan terdedah kepada penggantian, menurut penjelasan jangka hayat paparan Apple.
Ketiga, bezakan pembentangan yang ditutup daripada editor yang masih kelihatan tetapi kehilangan drafnya. Mulakan dengan contoh TextEditor biasa, kemudian tambahkan semula kandungan tersuai secara berperingkat. Perbandingan ini ialah kaedah diagnostik: ia membantu menentukan sama ada kegagalan berpunca daripada pemilikan pembentangan atau logik kemas kini kandungan anda.
Patutkah anda beralih kepada sheet yang dipacu item?
Gunakan sheet(item:onDismiss:content:) apabila entiti terpilih tertentu menjadi sumber pembentangan. Apple mendokumenkan item pilihan yang mematuhi Identifiable, menghantar item bukan-nil kepada penutup kandungan dan menerangkan penggantian apabila item berubah. Menukar overload tidak dengan sendirinya mengekalkan pembentang yang jangka hayatnya tamat. Lihat sheet yang dipacu item.
Pilih pengecam yang mewakili entiti sepanjang sesi pengeditan yang dikehendaki. Protokol Identifiable Swift menyatakan identiti stabil, dan dokumentasinya secara jelas menyerahkan tempoh serta skop yang diperlukan kepada jenis yang mengambil bahagian. Pengecam baharu setiap kali sifat dibaca tidak boleh mewakili entiti yang berterusan. Lihat Identifiable.
Bagi editor ringkas seperti demonstrasi ini, bendera pembentangan Boolean bersama binding teks berasingan memudahkan hubungan yang dimaksudkan untuk diperiksa. Bagi editor item terpilih, asingkan identiti pilihan daripada medan yang kerap berubah. Anggap pemilihan entiti lain sebagai keputusan pembentangan yang disengajakan, dan tentukan dahulu tindakan terhadap draf semasa.
Adakah penyahaktifan penutupan interaktif akan memastikan sheet kekal hidup?
interactiveDismissDisabled(_:) mengawal penutupan bukan programatik. Apple menyatakan dengan jelas bahawa ia tidak menghalang penutupan yang disebabkan oleh perubahan binding pembentangan atau panggilan kepada dismiss. Oleh itu, peranan yang didokumenkan tidak menyediakan penyelesaian bagi penggantian identiti. Lihat interactiveDismissDisabled(_:).
Gunakan pengubah suai ini di dalam hierarki sheet hanya apabila antara muka anda memerlukan tingkah laku penutupan itu, dan kekalkan laluan penyelesaian yang jelas. Untuk tugasan ini, mulakan dengan mengekalkan hos dan keadaannya. Menambah sekatan penutupan sebelum mengenal pasti punca boleh menyebabkan masalah pemilikan asal tidak selesai.
Apakah perubahan apabila sheet mengandungi kandungan AppKit atau TextKit?
Bagi NSTextView yang dibenamkan dengan NSViewRepresentable, asingkan penciptaan daripada kemas kini. Apple mentakrifkan makeNSView(context:) sebagai langkah penciptaan dan updateNSView(_:context:) sebagai tempat untuk menerapkan maklumat SwiftUI seterusnya. Penyelaras membawa perubahan perwakilan atau sasaran-tindakan kembali ke SwiftUI. Lihat NSViewRepresentable dan makeNSView(context:).
Peraturan pelaksanaan yang berguna berdasarkan kitar hayat ini ialah mengelakkan pembinaan semula editor hanya kerana keadaan pemilik yang tidak berkaitan berubah. Sebelum menggantikan kandungannya, tentukan sama ada teks model yang masuk benar-benar berbeza dan cara suntingan setempat serentak perlu dikendalikan. Sheet yang stabil sahaja tidak menyelesaikan penulisan yang bersaing pada teksnya.
TextKit menyediakan storan teks, susun atur dan pemaparan. NSTextView AppKit menggabungkan keupayaan tersebut serta mendedahkan enjin susun atur moden dan legasi. Mekanisme itu berkaitan dengan kandungan editor; pemilikan pembentangan masih memerlukan jangka hayatnya sendiri yang stabil. Gunakan TextKit apabila tugasan pengeditan memerlukannya, dan siasat tingkah laku kemas kini teks secara berasingan daripada penutupan sheet. Lihat gambaran keseluruhan TextKit Apple.
Bilakah pembentangan AppKit yang dimiliki tetingkap sesuai?
Jika app sedia ada anda sudah mengurus kitar hayat tetingkap dalam AppKit, macOS 26 memperkenalkan NSWindow.beginSheet(content:completionHandler:) untuk membentangkan kandungan SwiftUI secara langsung pada tetingkap itu. Apple mendokumenkan sokongan untuk tindakan persekitaran tutup sheet, saiz, bar alat dan kawalan penutupan interaktif. Gunakan SDK macOS 26 dan patuhi had ketersediaan macOS 26 sebelum menggunakannya. Lihat beginSheet(content:completionHandler:).
NSWindow.HostingSheetRepresentation yang dipulangkan boleh menukar paparan akar yang dibentangkan atau menyokong penutupan programatik daripada AppKit. Ia menawarkan pilihan yang didokumenkan apabila pemilikan peringkat tetingkap sesuai dengan seni bina app. Ia tidak diperlukan untuk contoh bekas SwiftUI stabil di atas. Lihat NSWindow.HostingSheetRepresentation.
Bagi versi macOS terdahulu, beginSheet(_:completionHandler:) sedia ada dalam AppKit menerima sheet NSWindow dan mendokumenkan giliran pembentangan. Jangan anggap overload kandungan SwiftUI yang lebih baharu tersedia pada sistem tersebut. Lihat beginSheet(_:completionHandler:).
Kekalkan pemilik yang stabil, pastikan nilai pembentangan aktif dan kekalkan sumber kebenaran editor yang dikehendaki. Sahkan syarat tersebut dengan tindakan kemas kini setempat yang ringkas sebelum mengembalikan kandungan yang lebih kompleks. Ini memberi anda cara yang jelas untuk terus mengedit semasa antara muka dikemas kini, dalam had jangka hayat dan API yang didokumenkan oleh Apple.
Sumber
- Demystify SwiftUI — Apple
- sheet(isPresented:onDismiss:content:) — Apple
- id(_:) — Apple
- State — Apple
- dismiss — Apple
- TextEditor — Apple
- sheet(item:onDismiss:content:) — Apple
- Identifiable — Apple
- interactiveDismissDisabled(_:) — Apple
- NSViewRepresentable — Apple
- makeNSView(context:) — Apple
- TextKit — Apple
- beginSheet(content:completionHandler:) — Apple
- NSWindow.HostingSheetRepresentation — Apple
- beginSheet(_:completionHandler:) — Apple