Untuk memaparkan tatasusunan Foundation dalam tetingkap Mac, sahkan jenis elemennya, kemudian cipta paparan bagi setiap nilai. Menjambatani NSArray kepada [String] memberikan anda rentetan; untuk memaparkannya, anda perlu menukarkannya secara berasingan kepada label AppKit.
Panduan ini ditujukan kepada pembangun yang menambahkan senarai kecil pada aplikasi macOS mereka sendiri. Tugas khususnya ialah memaparkan tiga nama sintetik—Circle, Square dan Triangle—dalam susunan menegak. Contoh ini menjelaskan jenis koleksi, jenis elemen, susun atur dan jangka hayat objek.
Apakah perubahan sebenar apabila koleksi dijambatani?
Apple mendokumenkan Array dan NSArray sebagai jenis Swift dan Foundation yang sepadan, sama seperti String dan NSString saling sepadan. Apple mengesyorkan penggunaan jenis nilai Swift dalam kod Swift biasa dan akses kepada jenis rujukan Foundation apabila tingkah lakunya diperlukan. Untuk tugas ini, kekalkan koleksi Foundation pada sempadan input dan gunakan tatasusunan Swift bertip selepas itu. Working with Foundation Types
Jenis luar koleksi dan jenis elemennya menjawab soalan yang berbeza. NSArray mengenal pasti koleksi objek tersusun. [String] menambah keperluan khusus: setiap elemen mesti boleh digunakan sebagai rentetan Swift. Tiada satu pun pengisytiharan itu menerangkan koleksi paparan. Pemula tindanan Apple secara jelas memerlukan [NSView]. NSArray, init(views:)
| Peringkat | Jenis dalam contoh ini | Kontrak |
|---|---|---|
| Input Foundation | NSArray |
Mengandungi objek sintetik yang dibekalkan |
| Model yang disahkan | [String] |
Setiap elemen memenuhi keperluan rentetan |
| Objek persembahan | [NSView] |
Setiap elemen ialah label teks yang baru dicipta |
| Bekas susun atur | NSStackView |
Menyusun paparan tersebut mengikut konfigurasinya |
Perbezaan penting ialah antara penjambatan dengan pembinaan. Penjambatan menghubungkan perwakilan yang disokong, seperti rentetan Foundation dan rentetan Swift. Membina objek NSTextField menghasilkan objek persembahan dengan sifat dan jangka hayatnya sendiri. Tiada jambatan rentetan-ke-label yang didokumenkan; cara yang disokong ialah memanggil pemula label bagi setiap rentetan. Array, init(labelWithString:)
Bagaimanakah anda mengesahkan elemen tanpa menggugurkan item?
Gunakan hantaran bersyarat apabila kontrak elemen koleksi masuk perlu diperiksa. Apple mendokumenkan bahawa as? menghasilkan keputusan pilihan dan hantaran paksa yang gagal dengan as! mencetuskan ralat masa jalan. Kendalikan kegagalan secara jelas sebelum membina antara muka. Handling Dynamically Typed Methods and Objects in Swift
Berikut ialah pemeriksaan lengkap yang hanya menggunakan Foundation dengan input sintetik. Simpan sebagai BridgeCheck.swift dan jalankannya pada Mac dengan alat Swift menggunakan swift BridgeCheck.swift. Asertasinya menyatakan hasil yang dijangka.
import Foundation
let source: NSArray = [
NSString(string: "Circle"),
NSString(string: "Square"),
NSString(string: "Triangle")
]
let names = source as? [String]
assert(names == ["Circle", "Square", "Triangle"])
let mixed: NSArray = [NSString(string: "Circle"), NSNumber(value: 7)]
assert((mixed as? [String]) == nil)
let empty: NSArray = []
assert((empty as? [String]) == [])
print("Collection checks passed.")
Hantaran pertama meminta tatasusunan rentetan, jadi ia memeriksa jenis elemen yang diperlukan semasa mendapatkan koleksi bertip. Input bercampur tidak dapat memenuhi kontrak itu. Input kosong boleh memenuhinya kerana tiada elemen yang tidak serasi. Ini ialah pemeriksaan ilustrasi bagi kontrak input yang dipilih, bukannya pengukuran atau hasil aplikasi.
Elakkan menggantikan compactMap { $0 as? String } semata-mata untuk membolehkan koleksi bercampur diterima. Apple mentakrifkan compactMap sebagai hanya mengembalikan hasil transformasi yang bukan nil. Dalam contoh ini, pendekatan itu akan membuang nombor tersebut lalu memaparkan senarai yang tidak lengkap. Penapisan mungkin sesuai apabila diminta secara jelas; di sini, tugasnya menghendaki setiap item yang dibekalkan dikekalkan. compactMap(_:)
Selepas pengesahan berjaya, gunakan map untuk mencipta satu label bagi setiap nama. Apple mendokumenkan map sebagai tindakan menggunakan transformasi pada elemen jujukan, dan NSTextField(labelWithString:) sebagai tindakan mencipta label statik yang tidak membalut teks dan teksnya tidak boleh dipilih. Oleh itu, transformasi ini sesuai untuk tiga nama pendek tersebut. map(_:), init(labelWithString:)
Bagaimanakah anda membina tetingkap Mac yang lengkap?
Contoh kendiri ini memerlukan macOS 14 atau lebih baharu serta alat baris perintah Xcode yang telah dipasang. Antara mukanya dibina secara programatik, jadi tiada papan cerita, nib, aset atau fail sumber tambahan diperlukan. Prasyarat macOS 14 meliputi penggunaan NSApplication.activate() dalam contoh ini, yang meminta pengaktifan tanpa menjaminnya. activate()
Simpan program lengkap di bawah sebagai CollectionDemo.swift. Program ini sengaja menyertakan titik masuknya sendiri. Apabila menyesuaikannya untuk aplikasi sedia ada, gunakan titik masuk dan kitar hayat yang telah ditetapkan oleh aplikasi tersebut dan bukannya menambah titik masuk kedua.
import Foundation
import AppKit
@MainActor
final class DemoDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow?
func applicationDidFinishLaunching(_ notification: Notification) {
let source: NSArray = [
NSString(string: "Circle"),
NSString(string: "Square"),
NSString(string: "Triangle")
]
guard let names = source as? [String] else {
print("Expected a collection containing only strings.")
NSApplication.shared.terminate(nil)
return
}
let labels: [NSView] = names.map { name in
NSTextField(labelWithString: name)
}
let stack = NSStackView(views: labels)
stack.orientation = .vertical
stack.alignment = .leading
stack.spacing = 8
stack.translatesAutoresizingMaskIntoConstraints = false
let content = NSView(frame: NSRect(
x: 0, y: 0, width: 360, height: 180
))
content.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(
equalTo: content.leadingAnchor, constant: 20
),
stack.topAnchor.constraint(
equalTo: content.topAnchor, constant: 20
),
stack.trailingAnchor.constraint(
lessThanOrEqualTo: content.trailingAnchor, constant: -20
),
stack.bottomAnchor.constraint(
lessThanOrEqualTo: content.bottomAnchor, constant: -20
)
])
let window = NSWindow(
contentRect: content.frame,
styleMask: [.titled, .closable, .miniaturizable],
backing: .buffered,
defer: false
)
window.title = "Synthetic Shapes"
window.isReleasedWhenClosed = false
window.contentView = content
self.window = window
window.center()
window.makeKeyAndOrderFront(nil)
NSApplication.shared.activate()
}
func applicationShouldTerminateAfterLastWindowClosed(
_ sender: NSApplication
) -> Bool {
true
}
}
@main
@MainActor
enum CollectionDemo {
static let appDelegate = DemoDelegate()
static func main() {
let app = NSApplication.shared
app.setActivationPolicy(.regular)
app.delegate = appDelegate
app.run()
}
}
Kompil dan lancarkannya dari Terminal dalam direktori yang mengandungi fail tersebut:
xcrun swiftc -parse-as-library CollectionDemo.swift -o CollectionDemo
./CollectionDemo
Dengan input yang dibekalkan, hasil yang dimaksudkan ialah tetingkap bertajuk Synthetic Shapes yang mengandungi tiga label mengikut susunan asalnya. Menutup tetingkapnya meminta aplikasi ditamatkan. Contoh ini mengembalikan true daripada kaedah perwakilan yang disediakan Apple untuk tingkah laku tersebut. applicationShouldTerminateAfterLastWindowClosed(_:)
Contoh ini telah diperiksa tetapi tidak dikompil atau dijalankan di sini: persekitaran penyelidikan tidak menyediakan pengkompil Swift mahupun AppKit macOS. Jalankan pemeriksaan Foundation dan periksa tetingkap itu pada Mac sasaran sebelum menyepadukan contoh ini.
Kontrak susun atur dan kitar hayat manakah yang mesti dikekalkan?
Nilai lalai pemula tindanan yang didokumenkan adalah penting: ia mencipta tindanan mendatar, meletakkan paparan yang dibekalkan dalam kawasan graviti utama dan menyahdayakan terjemahan topeng saiz semula automatik untuk tindanan tersebut. Contoh ini secara jelas menukar orientasi kepada menegak dan penjajaran kepada utama. Hantaran tatasusunan tidak boleh menentukan mana-mana tetapan susun atur itu. init(views:), alignment
Tindanan mengurus susunan paparan yang terkandung di dalamnya. Kekangan antara tindanan dengan paparan kandungan yang membungkusnya menentukan kedudukan susunan itu dalam tetingkap. Di sini, kekangan utama dan atas menetapkan jidar 20 titik; ketaksamaan kanan dan bawah menyediakan ruang tanpa memerlukan senarai pendek itu memenuhi kawasan kandungan. Apple mendokumenkan bahawa paparan tindanan menggunakan Auto Layout dan menerangkan bahawa penyahdayaan terjemahan topeng saiz semula automatik membolehkan anda menetapkan kekangan sendiri. NSStackView, translatesAutoresizingMaskIntoConstraints
Ini ialah demonstrasi bersaiz tetap untuk tiga label pendek. Teks yang lebih panjang, banyak baris atau antara muka yang boleh diubah saiznya memerlukan keputusan susun atur yang berasingan—seperti pembalutan atau penatalan—sebelum contoh ini diperluas. Kejayaan menjambatani koleksi yang lebih besar tidak membuktikan bahawa kandungannya muat apabila dipaparkan.
Jangka hayat juga berasingan daripada penukaran jenis. Apple mengisytiharkan sifat perwakilan aplikasi sebagai lemah. Oleh itu, sifat statik appDelegate menyediakan pemilik kuat yang jelas. Perwakilan itu juga mengekalkan tetingkap, dan tetingkap menetapkan isReleasedWhenClosed kepada false, mengikut panduan Apple untuk klien Swift dan ARC. delegate, isReleasedWhenClosed
Pembinaan antara muka berlaku dalam applicationDidFinishLaunching, yang didokumenkan Apple sebagai tempat untuk pemulaan tambahan selepas gelung utama bermula dan sebelum ia memproses peristiwa. Titik masuk program memanggil run() untuk memulakan gelung peristiwa itu. Kekalkan tanggungjawab tersebut apabila memindahkan penukaran ini ke dalam aplikasi AppKit sedia ada. applicationDidFinishLaunching(_:), run()
Label tersebut juga mewakili petikan yang dibina. Contoh ini menetapkan teks setiap label sekali sahaja. Jika koleksi sumber berubah selepas itu, kod yang jelas diperlukan untuk mengemas kini label atau membina semula paparan tersusun; operasi penjambatan dan pemetaan tidak mewujudkan sambungan berterusan.
Bagaimanakah anda boleh mengenal pasti kesilapan bekas-berbanding-elemen dengan cepat?
Gunakan urutan berikut untuk mengenal pasti kontrak yang gagal. Urutan ini memisahkan pengesahan jenis daripada pemeriksaan persembahan dan kitar hayat, supaya masalah susun atur tidak menyebabkan anda menulis semula penjambatan yang sudah berjaya.
| Gejala | Perkara yang perlu diperiksa | Langkah seterusnya yang disokong |
|---|---|---|
Hantaran kepada [String] mengembalikan nil |
Adakah setiap elemen input memenuhi keperluan rentetan? | Tolak koleksi itu secara jelas atau tetapkan dasar penukaran yang disengajakan. |
Seluruh tatasusunan sedang dihantar kepada String |
Adakah destinasi memerlukan satu nilai atau koleksi? | Sahkan [String]; pilih elemen hanya jika tugas itu benar-benar memerlukannya. |
| Pemula tindanan menolak argumen | Adakah argumen itu [String] dan bukannya [NSView]? |
Petakan setiap rentetan kepada label dahulu. |
| Label dipaparkan secara mendatar | Adakah orientasi tindanan telah dikonfigurasikan? | Tetapkan .vertical untuk senarai ini. |
| Kedudukan paparan salah atau kekangan bercanggah | Adakah kekangan paparan pembungkus dan tetapan topeng saiz semula automatik konsisten? | Periksa susun atur secara berasingan daripada hantaran input. |
| Panggilan balik perwakilan tidak diterima | Adakah pemilik kuat mengekalkan perwakilan itu? | Pastikan perwakilan kekal hidup selepas ditetapkan kepada sifat lemah. |
| Perubahan model kemudian tidak dipaparkan | Adakah terdapat kod kemas kini yang jelas? | Kemas kini nilai label atau paparan tersusun secara sengaja. |
Untuk tugas ini, cara yang boleh diharapkan ialah mengesahkan input Foundation sekali, mengekalkan model bertip yang terhasil, membina satu label bagi setiap nilai dan mengkonfigurasikan tindanan serta jangka hayat aplikasi secara jelas. Setiap langkah mempunyai kontrak yang nyata, menjadikan kegagalan lebih mudah didiagnosis apabila antara muka Mac berkembang.
Sumber
Working with Foundation Types — Apple
NSArray — Apple
Array — Apple
Handling Dynamically Typed Methods and Objects in Swift — Apple
compactMap(_:) — Apple
map(_:) — Apple
init(labelWithString:) — Apple
NSStackView — Apple
init(views:) — Apple
alignment — Apple
delegate — Apple
isReleasedWhenClosed — Apple
run() — Apple
activate() — Apple