Mac विंडो में Foundation array दिखाने के लिए, उसके तत्वों के प्रकार की पुष्टि करें, फिर हर मान के लिए एक view बनाएँ। NSArray को [String] में ब्रिज करने से आपको strings मिलती हैं; उन्हें दिखाने के लिए AppKit लेबल में एक अलग रूपांतरण करना पड़ता है।
यह वॉकथ्रू उस डेवलपर के लिए है जो अपने macOS ऐप में एक छोटी सूची जोड़ रहा है। ठोस काम तीन कृत्रिम नामों—Circle, Square, और Triangle—को एक ऊर्ध्वाधर स्टैक में दिखाना है। इस उदाहरण में collection के प्रकार, तत्वों के प्रकार, लेआउट और ऑब्जेक्ट का जीवनकाल स्पष्ट रखे गए हैं।
किसी collection को ब्रिज करने से वास्तव में क्या बदलता है?
Apple, Array और NSArray को Swift और Foundation के अनुरूप प्रकारों के रूप में दस्तावेज़ित करता है, ठीक वैसे ही जैसे String और NSString अनुरूप हैं। इसकी सिफारिश है कि सामान्य Swift कोड में Swift के value types इस्तेमाल करें और Foundation के reference types तक तब पहुँचें जब उनके व्यवहार की ज़रूरत हो। इस काम के लिए, इनपुट सीमा पर Foundation collection रखें और उसके बाद एक typed Swift array इस्तेमाल करें। Foundation प्रकारों के साथ काम करना
Collection का बाहरी प्रकार और उसके तत्वों का प्रकार अलग-अलग सवालों के जवाब देते हैं। NSArray एक क्रमबद्ध ऑब्जेक्ट collection की पहचान करता है। [String] एक विशिष्ट शर्त जोड़ता है: हर तत्व को Swift string के रूप में इस्तेमाल किया जा सके। इनमें से कोई भी घोषणा views के collection का वर्णन नहीं करती। Apple का stack initializer स्पष्ट रूप से [NSView] की माँग करता है। NSArray, init(views:)
| चरण | इस उदाहरण में प्रकार | अनुबंध |
|---|---|---|
| Foundation इनपुट | NSArray |
दिए गए कृत्रिम ऑब्जेक्ट शामिल हैं |
| सत्यापित मॉडल | [String] |
हर तत्व string की शर्त पूरी करता है |
| प्रस्तुति ऑब्जेक्ट | [NSView] |
हर तत्व एक नया बनाया गया टेक्स्ट लेबल है |
| लेआउट कंटेनर | NSStackView |
अपने कॉन्फ़िगरेशन के अनुसार उन views को व्यवस्थित करता है |
उपयोगी अंतर ब्रिजिंग और निर्माण के बीच है। ब्रिजिंग संगत निरूपणों को जोड़ती है, जैसे Foundation strings और Swift strings। NSTextField ऑब्जेक्ट बनाना ऐसे प्रस्तुति ऑब्जेक्ट बनाता है जिनके अपने गुण और जीवनकाल होते हैं। string से label में बदलने वाला कोई दस्तावेज़ित bridge नहीं है; समर्थित तरीका है हर string के लिए label initializer कॉल करना। Array, init(labelWithString:)
तत्वों को छोड़े बिना उनकी पुष्टि कैसे करें?
जब आने वाले collection के तत्वों के अनुबंध की जाँच करनी हो, तो conditional cast इस्तेमाल करें। Apple दस्तावेज़ित करता है कि as? एक optional परिणाम देता है और as! से असफल forced cast रनटाइम त्रुटि पैदा करता है। इंटरफ़ेस बनाने से पहले विफलता को स्पष्ट रूप से संभालें। Swift में डायनेमिक रूप से टाइप किए गए तरीकों और ऑब्जेक्ट के साथ काम करना
नीचे कृत्रिम इनपुट के साथ केवल Foundation का इस्तेमाल करके की गई पूरी जाँच दी गई है। इसे BridgeCheck.swift नाम से सेव करें और Mac पर Swift टूल्स के साथ swift BridgeCheck.swift चलाएँ। इसके assertions अपेक्षित परिणाम बताते हैं।
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.")
पहला cast strings का array माँगता है, इसलिए typed collection प्राप्त करते समय यह ज़रूरी element type की जाँच भी करता है। मिश्रित इनपुट यह शर्त पूरी नहीं कर सकता। खाली इनपुट कर सकता है: उसमें कोई असंगत तत्व नहीं है। ये चुने गए इनपुट अनुबंध की उदाहरणात्मक जाँचें हैं, माप या ऐप्लिकेशन के परिणाम नहीं।
मिश्रित collection को स्वीकार कराने के लिए केवल compactMap { $0 as? String } का विकल्प न अपनाएँ। Apple, compactMap को ऐसे transformation परिणाम लौटाने वाला बताता है जो nil नहीं हैं। इस उदाहरण में, ऐसा करने से संख्या छूट जाएगी और सूची अधूरी दिखेगी। स्पष्ट रूप से अनुरोध किए जाने पर filtering उपयुक्त हो सकती है; यहाँ काम के लिए दिए गए हर आइटम को बनाए रखना ज़रूरी है। compactMap(_:)
पुष्टि सफल होने पर, हर नाम के लिए एक लेबल बनाने हेतु map इस्तेमाल करें। Apple, map को sequence के तत्वों पर transformation लागू करने वाला और NSTextField(labelWithString:) को static, nonwrapping label बनाने वाला, जिसमें टेक्स्ट चुना नहीं जा सकता, दस्तावेज़ित करता है। इससे यह transformation इन तीन छोटे नामों के लिए उपयुक्त है। map(_:), init(labelWithString:)
पूरी Mac विंडो कैसे बनाएँ?
इस standalone उदाहरण के लिए macOS 14 या उसके बाद का संस्करण और इंस्टॉल किए हुए Xcode command-line tools ज़रूरी हैं। यह अपना इंटरफ़ेस प्रोग्राम के ज़रिए बनाता है, इसलिए किसी storyboard, nib, asset या अतिरिक्त source file की ज़रूरत नहीं है। macOS 14 की पूर्वापेक्षा उदाहरण में NSApplication.activate() के इस्तेमाल को कवर करती है, जो activation का अनुरोध करता है, लेकिन इसकी गारंटी नहीं देता। activate()
नीचे दिए गए पूरे प्रोग्राम को CollectionDemo.swift नाम से सेव करें। इसमें जानबूझकर इसका अपना entry point शामिल है। किसी मौजूदा ऐप में इसे अपनाते समय दूसरा entry point जोड़ने के बजाय उस ऐप का स्थापित entry point और lifecycle इस्तेमाल करें।
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()
}
}
फ़ाइल वाली डायरेक्टरी में Terminal खोलकर इसे compile और launch करें:
xcrun swiftc -parse-as-library CollectionDemo.swift -o CollectionDemo
./CollectionDemo
दिए गए इनपुट के साथ अपेक्षित परिणाम Synthetic Shapes शीर्षक वाली विंडो है, जिसमें तीनों लेबल मूल क्रम में दिखते हैं। विंडो बंद करने पर ऐप्लिकेशन समाप्त करने का अनुरोध होता है। नमूना उस delegate method से true लौटाता है जिसे Apple इस व्यवहार के लिए देता है। applicationShouldTerminateAfterLastWindowClosed(_:)
यहाँ इन उदाहरणों का निरीक्षण किया गया, लेकिन इन्हें compile या execute नहीं किया गया: research environment में न Swift compiler है, न macOS AppKit। उदाहरण को एकीकृत करने से पहले Foundation जाँच चलाएँ और लक्षित Mac पर विंडो देखें।
लेआउट और जीवनचक्र के किन अनुबंधों को बनाए रखना चाहिए?
Stack initializer के दस्तावेज़ित defaults महत्वपूर्ण हैं: यह horizontal stack बनाता है, दिए गए views को उसके leading gravity area में रखता है और stack के लिए autoresizing-mask translation बंद करता है। उदाहरण orientation को स्पष्ट रूप से vertical और alignment को leading पर बदलता है। Array cast इनमें से कोई भी layout setting नहीं चुन सकता। init(views:), alignment
Stack अपने अंदर रखे views की व्यवस्था संभालता है। Stack और उसे घेरने वाले content view के बीच constraints यह तय करते हैं कि विंडो में वह व्यवस्था कहाँ होगी। यहाँ leading और top constraints 20-point inset तय करते हैं; trailing और bottom की inequalities जगह आरक्षित रखती हैं, लेकिन छोटी सूची को पूरा content area भरने के लिए बाध्य नहीं करतीं। Apple दस्तावेज़ित करता है कि stack views Auto Layout का इस्तेमाल करते हैं और बताता है कि autoresizing-mask translation बंद करने से आप खुद constraints दे सकते हैं। NSStackView, translatesAutoresizingMaskIntoConstraints
यह तीन छोटे लेबलों के लिए निश्चित आकार वाला प्रदर्शन है। लंबे टेक्स्ट, कई पंक्तियों या आकार बदल सकने वाले इंटरफ़ेस के लिए नमूने को विस्तृत करने से पहले अलग लेआउट निर्णय—जैसे टेक्स्ट wrap करना या scrolling—लेना होगा। किसी बड़े collection को सफलतापूर्वक ब्रिज करने से यह तय नहीं होता कि उसकी प्रस्तुति उपलब्ध जगह में फिट होगी।
जीवनकाल भी प्रकार-रूपांतरण से अलग है। Apple, ऐप्लिकेशन की delegate property को weak घोषित करता है। इसलिए static appDelegate property एक स्पष्ट strong owner देती है। delegate विंडो को भी बनाए रखता है और विंडो isReleasedWhenClosed को false पर सेट करती है—यह Swift और ARC clients के लिए Apple के मार्गदर्शन के अनुसार है। delegate, isReleasedWhenClosed
इंटरफ़ेस का निर्माण applicationDidFinishLaunching में होता है। Apple इसे मुख्य loop शुरू होने के बाद और उसके events संसाधित करने से पहले अतिरिक्त initialization करने की जगह के रूप में दस्तावेज़ित करता है। प्रोग्राम का entry point उस event loop को शुरू करने के लिए run() कॉल करता है। इस रूपांतरण को किसी मौजूदा AppKit ऐप में ले जाते समय इन ज़िम्मेदारियों को बनाए रखें। applicationDidFinishLaunching(_:), run()
ये लेबल बनाए गए snapshot को भी दर्शाते हैं। उदाहरण हर लेबल का टेक्स्ट एक बार सेट करता है। इसके बाद source collection बदलने पर लेबल अपडेट करने या arranged views दोबारा बनाने के लिए स्पष्ट कोड चाहिए; bridge और mapping operation अपने-आप कोई निरंतर संबंध स्थापित नहीं करते।
कंटेनर और तत्व की गलती का जल्दी पता कैसे लगाएँ?
कौन-सा अनुबंध विफल हुआ, यह पहचानने के लिए यह क्रम अपनाएँ। इससे प्रकार की पुष्टि को प्रस्तुति और जीवनचक्र की जाँच से अलग रखा जाता है, ताकि layout की समस्या के कारण आपको सफल bridge को फिर से लिखना न पड़े।
| लक्षण | जाँचें | समर्थित अगला कदम |
|---|---|---|
[String] में cast करने पर nil मिलता है |
क्या हर इनपुट तत्व string की शर्त पूरी करता है? | Collection को स्पष्ट रूप से अस्वीकार करें या जानबूझकर रूपांतरण नीति तय करें। |
पूरे array को String में cast किया जा रहा है |
क्या destination को एक मान चाहिए या collection? | [String] की पुष्टि करें; कोई तत्व तभी चुनें जब काम में सचमुच एक तत्व चाहिए। |
| Stack initializer argument स्वीकार नहीं करता | क्या argument [String] है, [NSView] नहीं? |
पहले हर string को label में बदलें। |
| लेबल horizontal दिखाई देते हैं | क्या stack orientation कॉन्फ़िगर की गई है? | इस सूची के लिए .vertical सेट करें। |
| Views गलत जगह हैं या constraints में टकराव है | क्या enclosing-view constraints और autoresizing-mask settings एक-दूसरे के अनुरूप हैं? | इनपुट cast से अलग layout की जाँच करें। |
| Delegate callbacks नहीं आते | क्या कोई strong owner delegate को बनाए रखता है? | weak property को असाइन करने के बाद भी delegate को जीवित रखें। |
| बाद के model बदलाव दिखाई नहीं देते | क्या अपडेट करने का स्पष्ट कोड है? | लेबल के मान या arranged views को जानबूझकर अपडेट करें। |
इस काम के लिए भरोसेमंद तरीका है Foundation इनपुट की एक बार पुष्टि करना, उससे बने typed model को बनाए रखना, हर मान के लिए एक लेबल बनाना और stack तथा ऐप के जीवनकाल को स्पष्ट रूप से कॉन्फ़िगर करना। हर चरण का अनुबंध दिखाई देता है, जिससे Mac इंटरफ़ेस बढ़ने पर समस्याओं का पता लगाना आसान होता है।
स्रोत
NSArray — Apple
Array — Apple
Swift में डायनेमिक रूप से टाइप किए गए तरीकों और ऑब्जेक्ट के साथ काम करना — Apple
compactMap(_:) — Apple
map(_:) — Apple
init(labelWithString:) — Apple
NSStackView — Apple
init(views:) — Apple
alignment — Apple
delegate — Apple
isReleasedWhenClosed — Apple
run() — Apple
activate() — Apple