Gunakan sheet(item:onDismiss:content:) dengan satu item terpilih opsional, dan bangun sheet dari item yang diterima closure-nya. Hal ini memberi aplikasi Mac satu nilai yang menentukan baik apakah akan mempresentasikan sheet maupun apa yang ditampilkan.
Tutorial ini mengimplementasikan tugas desktop kecil: klik item sampel lokal dan periksa detailnya segera. Ia juga menyediakan urutan diagnostik untuk sheet yang terbuka kosong, menampilkan pemilihan sebelumnya, atau menampilkan teks usang di dalam view AppKit.
Mengapa menggunakan sheet berbasis item?
SwiftUI menawarkan dua metode presentasi yang relevan. Overload Boolean mempresentasikan ketika binding-nya menjadi true. Overload item menerima nilai identifiable opsional dan menyuplai nilai itu ke closure konten. Pilih bentuk Boolean untuk panel tetap; pilih bentuk item ketika konten panel bergantung pada pemilihan. Lihat dokumentasi Apple untuk sheet berbasis Boolean dan sheet berbasis item.
Desain dengan properti pemilihan dan presentasi terpisah mengizinkan kombinasi seperti presentasi yang diminta tanpa pemilihan. Menggabungkannya menjadi satu nilai opsional menghapus kombinasi itu dari model state Anda sendiri: nil mewakili tidak ada item yang diminta, dan nilai terisi mewakili item yang akan diperiksa. Ini adalah deduksi desain dari dua API, bukan klaim tentang cacat penjadwalan SwiftUI yang tidak terdokumentasikan.
Jika implementasi yang ada menetapkan pemilihan lalu mengalihkan Boolean, kedua pernyataan itu saja tidak menetapkan mengapa presentasi pertamanya gagal. Periksa jalur data konten sebelum mengaitkan gejala dengan timing. Pertanyaan yang berguna adalah apakah sheet me-render input yang disuplainya, membaca properti lain, atau menampilkan salinan terpisah yang disimpan secara terpisah.
Bangun contoh macOS lengkap
Buat project aplikasi macOS di Xcode dengan antarmuka SwiftUI. Gunakan target deployment macOS 12 atau lebih baru untuk contoh ini. API sheet berbasis item berasal dari macOS 10.15, sedangkan environment dismissal action yang digunakan di bawah memerlukan macOS 12. Batasan ketersediaan ini terdokumentasi oleh Apple untuk sheet berbasis item dan nilai environment dismissal.
Gantikan deklarasi app dan content view yang di-generate dengan program lengkap ini. Pertahankan hanya satu entry point app di target. Semua label dan deskripsi di bawah adalah data sampel lokal sintetis.
import SwiftUI
struct SampleItem: Identifiable {
let id: String
let title: String
let detail: String
}
@main
struct FirstSheetDemoApp: App {
var body: some Scene {
WindowGroup {
ItemListView()
}
}
}
struct ItemListView: View {
private let items = [
SampleItem(
id: "tile-a",
title: "Amber Tile",
detail: "A square sample with an amber finish."
),
SampleItem(
id: "tile-b",
title: "Blue Tile",
detail: "A rectangular sample with a blue finish."
)
]
@State private var presentedItem: SampleItem? = nil
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Sample Items")
.font(.title2)
ForEach(items) { item in
Button("Inspect \(item.title)") {
presentedItem = item
}
}
}
.padding(24)
.frame(minWidth: 360, minHeight: 200)
.sheet(item: $presentedItem) { item in
ItemDetailView(item: item)
}
}
}
struct ItemDetailView: View {
let item: SampleItem
@Environment(\.dismiss) private var dismiss
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text(item.title)
.font(.title)
Text(item.detail)
Text("Item ID: \(item.id)")
.font(.caption)
HStack {
Spacer()
Button("Done") {
dismiss()
}
}
}
.padding(24)
.frame(width: 380, height: 220)
}
}
Tombol menetapkan nilai yang diklik ke presentedItem. Closure presentasi lalu meneruskan parameter item-nya sendiri ke ItemDetailView. Perhatikan bahwa detail view memiliki properti input biasa, let item, bukan properti state item-terpilih kedua. Apple menyarankan menjaga single source of truth dan berbagi nilai read-only melalui properti, menggunakan binding ketika child memerlukan akses tulis. Lihat State.
Dismissal action berada di dalam ItemDetailView, di mana ia membaca environment sheet. Apple secara eksplisit memperingatkan bahwa membacanya di presenting view dan memanggil action tersebut dari konten sheet menggunakan environment presenting view. Simpan deklarasi di samping konten sheet sendiri, seperti yang ditunjukkan. Lihat dismiss.
Program ini telah diperiksa untuk input dan referensi yang konsisten; ia tidak dikompilasi atau dijalankan di sini karena toolchain Swift tidak tersedia di lingkungan ini. Jalankan pemeriksaan berikut di Xcode pada versi macOS target Anda.
Verifikasi presentasi pertama dengan urutan klik yang disengaja
Mulai setiap pemeriksaan presentasi pertama dengan launch segar. Hanya menguji setelah membuka item lain dapat menyembunyikan gejala asli. Ekspektasi berikut berasal dari label dan penugasan data eksplisit sampel; mereka adalah kriteria penerimaan, bukan hasil tes yang dilaporkan.
| Aksi | Konten sheet yang diharapkan | Apa yang diperiksa |
|---|---|---|
Launch dan klik Inspect Blue Tile pertama |
Blue Tile, deskripsi rectangular-nya, dan tile-b |
Presentasi pertama menggunakan item yang diklik |
Klik Done, lalu inspect Amber Tile |
Amber Tile, deskripsi square-nya, dan tile-a |
Pemilihan subsequent menjangkau konten |
Dismiss dan inspect Amber Tile lagi |
Detail amber yang sama | Membuka item kembali tetap konsisten |
Relaunch dan inspect Amber Tile pertama |
Detail amber segera | Kebenaran tidak bergantung pada sampel mana yang dibuka pertama |
Menampilkan baik title maupun ID membuat pemeriksaan ini lebih berguna daripada memeriksa title saja. Jika antarmuka nyata Anda mengizinkan nama tampilan duplikat, gunakan dua item sintetis dengan title yang sama dan ID serta deskripsi berbeda selama pengembangan. Hal itu mengekspos pemilihan acidental berdasarkan teks tampilan.
Diagnosis konten usang dari tombol ke view final
Bekerja melalui pemeriksaan ini secara berurutan. Setiap langkah menyempitkan lokasi ketidakcocokan, sehingga Anda bisa mengubah layer yang bertanggung jawab tanpa menambah workaround presentasi yang tidak terkait.
- Periksa input action. Set breakpoint di action tombol yang diklik dan inspeksi
item.id. Konfirmasi bahwa action menerima record yang dimaksud. - Periksa input presentasi. Inspeksi parameter
itemdi dalam closure sheet. Teruskan parameter itu ke detail view daripada mencari pemilihan terpisah lagi. - Periksa properti tampilan final. Konfirmasi bahwa title dan deskripsi dibaca dari input detail view. Cari properti cached atau draft lokal yang berisi nilai sebelumnya.
- Periksa bridge AppKit apa pun. Jika teks SwiftUI biasa benar tapi teks wrapped usang, inspeksi method update representable.
Jaga identitas stabil
API berbasis item memerlukan Identifiable. Swift mendefinisikan protokol itu di sekitar identitas stabil dan menyerahkan durasi dan scope-nya ke tipe yang conform dan konsumennya. Sampel menggunakan ID string tersimpan yang membedakan dua record. Lihat Identifiable.
Untuk list nyata, pilih identifier yang terus mengidentifikasi record yang sama di seluruh update yang didukung antarmuka Anda. Hindari menurunkan identitas dari title yang bisa berubah atau dibagi beberapa item. Hindari juga id computed yang menciptakan UUID baru setiap kali dibaca; itu tidak akan menyediakan identitas stabil.
Pisahkan input tampilan dari draft yang bisa diedit
Sebuah inspector bisa menampilkan item.title langsung. Sebuah editor mungkin sengaja menciptakan draft lokal, tapi draft memperkenalkan nilai lain yang lifetime-nya harus didefinisikan. Tentukan kapan ia dibuat, apakah perubahan model nanti harus menggantikannya, dan apa yang terjadi ketika user selesai atau membatalkan.
Apple menjelaskan bahwa SwiftUI mempertahankan penyimpanan state untuk identitas view dan menginisialisasi di awal lifetime identitas tersebut. Menciptakan ulang nilai view tidak secara inheren menciptakan state baru. Akibatnya, menginisialisasi state lokal dari input bukan mekanisme umum untuk menjaga state itu tersinkronisasi dengan input nanti. Lihat Demystify SwiftUI.
Untuk tugas read-only ini, pertahankan properti input biasa. Jika Anda memperluasnya ke editing, pilih desain draft-and-commit eksplisit atau binding ke nilai model yang dimaksud. Hindari menambah identitas view yang berubah hanya untuk me-refresh teks: mengubah identitas mengganti state terkait, yang bisa membuang draft yang belum selesai. Konsekuensi itu mengikuti model lifetime state yang terdokumentasi Apple.
Apa yang berubah ketika sheet berisi AppKit text view?
Sheet yang berisi NSTextView tetap memerlukan jalur data item-terpilih yang sama. Ia juga memerlukan bridge yang diimplementasikan dengan benar. Protokol NSViewRepresentable Apple memisahkan pembuatan awal di makeNSView(context:) dari konfigurasi subsequent di updateNSView(_:context:). Wrapper yang menetapkan teksnya hanya selama pembuatan tidak memiliki implementasi untuk menerapkan input teks nanti. Lihat NSViewRepresentable.
Untuk wrapper read-only, inisialisasi native view dengan teks yang disuplai dan biarkan method update-nya membawa teks tampilan menjadi sepakat dengan input saat ini ketika perlu. Apple mendokumentasikan bahwa SwiftUI memanggil method update untuk perubahan yang mempengaruhi AppKit view yang sesuai. Lihat updateNSView(_:context:).
Wrapper editable memerlukan kebijakan tambahan: jangan buta mengganti teksnya pada setiap update dan menimpa edit yang sedang berlangsung. Gunakan coordinator untuk mengomunikasikan perubahan delegate native atau target-action kembali ke SwiftUI, seperti yang dijelaskan Apple di dokumentasi representable. Biarkan SwiftUI mengontrol frame dan bounds represented view; Apple memperingatkan against langsung menetapkan properti layout tersebut.
TextKit menangani penyimpanan teks, layout, dan rendering. Apple mendokumentasikan baik path modern NSTextLayoutManager maupun legacy NSLayoutManager yang diekspos oleh NSTextView. Fasilitas tersebut tidak menyuplai record terpilih sheet. Pastikan bridge menerima teks item yang benar sebelum menyelidiki text layout, dan periksa ketersediaan terpisah sebelum memperkenalkan API TextKit tambahan. Lihat TextKit.
Pilih model presentasi yang cocok dengan tugas
Gunakan overload Boolean ketika konten tetap dan visibility adalah input berubah satu-satunya. Gunakan overload item untuk tugas inspector ini. Apple mendokumentasikan bahwa mengubah item yang disuplai bisa dismiss dan mengganti sheet existing, jadi jangan memperlakukan penggantian item sebagai janji editing tidak terputus dalam presentasi yang sama. Lihat sheet(item:onDismiss:content:).
Untuk presentasi pertama yang benar, buat record terpilih mudah ditelusuri: satu assignment di action tombol, satu parameter item di closure sheet, dan satu input di detail view. Verifikasi kedua item sampel dari launch segar. Jika hasil masih berbeda, urutan diagnostik mengidentifikasi apakah ketidakcocokan masuk melalui seleksi, state retained, atau path update native-view.
Sumber
- sheet(item:onDismiss:content:) — Apple
- sheet(isPresented:onDismiss:content:) — Apple
- State — Apple
- dismiss — Apple
- Identifiable — Apple
- Demystify SwiftUI — Apple
- NSViewRepresentable — Apple
- updateNSView(_:context:) — Apple
- TextKit — Apple