अपडेट के दौरान SwiftUI शीट खुली रखने के लिए, उसकी प्रस्तुति होस्ट की पहचान बनाए रखें और प्रस्तुति बाइंडिंग सक्रिय रखें। शीट को किसी स्थिर कंटेनर से जोड़ें, ताकि प्रस्तुतकर्ता को बदले बिना बदलती हुई चाइल्ड सामग्री अपडेट हो सके।
यह मार्गदर्शिका ऐसे डेवलपर के लिए है जो Mac ऐप में संपादन योग्य शीट बना रहा है, जिसे अंतर्निहित इंटरफ़ेस बदलने पर भी दिखाई देते रहना चाहिए। उदाहरण में कृत्रिम स्थानीय टेक्स्ट का उपयोग किया गया है और तीन चीज़ों को अलग रखा गया है, जिनका आप स्वतंत्र रूप से निरीक्षण कर सकते हैं: प्रस्तुति स्थिति, प्रस्तुत करने वाले दृश्य का जीवनकाल और संपादक की सामग्री।
दृश्य अपडेट होने पर शीट क्यों गायब हो सकती है?
body का मूल्यांकन करते समय SwiftUI नए दृश्य मान बना सकता है, जबकि प्रदर्शित दृश्य की पहचान बनाए रखता है। स्थिति उस पहचान के जीवनकाल तक बनी रहती है। दृश्य हटाने या उसकी पहचान बदलने से वह जीवनकाल समाप्त हो जाता है; सशर्त शाखाओं के बीच स्विच करने से भी अलग-अलग पहचान बन सकती हैं, भले ही दोनों शाखाओं में दृश्य का प्रकार समान हो। Apple इन संबंधों को SwiftUI को समझें में समझाता है।
बूलियन-आधारित शीट के लिए, दस्तावेज़ीकृत प्रस्तुति नियंत्रण sheet(isPresented:onDismiss:content:) को दी गई बाइंडिंग है: true मान प्रस्तुति का अनुरोध करता है। गायब होती शीट की जाँच करते समय, उस बाइंडिंग और संशोधक वाले दृश्य के बने रहने—दोनों की जाँच करें। कहीं और संग्रहीत true मान यह साबित नहीं करता कि मूल प्रस्तुति होस्ट बना रहा। Apple का बूलियन शीट दस्तावेज़ीकरण देखें।
एक खास तौर पर सीधा कारण बदलता हुआ स्पष्ट पहचानकर्ता है। Apple दस्तावेज़ीकृत करता है कि id(_:) को दिए गए मान में बदलाव दृश्य की पहचान रीसेट करता है, जिसमें उसकी स्थिति भी शामिल है। प्रस्तुत करने वाले दृश्य और उसके पूर्वजों में ऐसे पहचानकर्ताओं की जाँच करें जो संशोधन काउंटर, संपादन योग्य टेक्स्ट या नए बनाए गए मानों से निकलते हों। जब उनका रीसेट व्यवहार अनचाहा हो, तो ऐसे पहचानकर्ता हटा दें। id(_:) देखें।
व्यावहारिक डिज़ाइन निष्कर्ष यह है कि शीट संशोधक को इंटरफ़ेस के बदलते हिस्से के बाहर रखा जाए। यदि लोडिंग दृश्य, फ़िल्टर की गई पंक्ति या वैकल्पिक विवरण लेआउट हट सकता है, तो उसका सबसे निकट का उपयुक्त स्थायी पूर्वज आम तौर पर प्रस्तुति का बेहतर स्वामी होता है।
Mac का पूरा उदाहरण लेकर स्थिर शीट स्वामी बनाएँ
Xcode में macOS SwiftUI ऐप बनाएँ, उसका डिप्लॉयमेंट लक्ष्य macOS 12 या बाद का रखें, और ऐप तथा कंटेंट दृश्य की बनाई गई घोषणाओं को नीचे दी गई एकल फ़ाइल से बदलें। केवल एक @main ऐप घोषणा रखें। macOS 12 का न्यूनतम संस्करण उदाहरण की dismiss एनवायरनमेंट कार्रवाई के लिए पर्याप्त है; TextEditor स्वयं macOS 11 से उपलब्ध है। Apple का dismiss दस्तावेज़ीकरण और TextEditor दस्तावेज़ीकरण देखें।
विंडो का रूट दृश्य प्रस्तुति फ़्लैग, संपादन योग्य टेक्स्ट, संशोधन काउंटर और लेआउट फ़्लैग का स्वामी है। इसका बाहरी VStack शीट संशोधक रखता है। केवल उस कंटेनर के अंदर की सामग्री शाखाएँ बदलती है। Apple सलाह देता है कि स्थिति को निजी रूप से उस सबसे ऊँचे दृश्य में घोषित करें जिसे इसकी ज़रूरत है और जिन चिल्ड्रन को इसे बदलना है, उन्हें बाइंडिंग दें। 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)
}
}
यह दस्तावेज़ीकृत API के आधार पर जाँचा गया एक संपूर्ण प्रदर्शन ऐप है। यहाँ इसे कंपाइल या चलाया नहीं गया है, क्योंकि इस परिवेश में Swift टूलचेन या macOS रनटाइम नहीं है।
शीट बंद किए बिना अपडेट कैसे करें
- ऐप चलाएँ और
Edit Noteपर क्लिक करें। - नमूना टेक्स्ट को
Sample note Betaसे बदलें। Update Ownerपर कई बार क्लिक करें। हर क्लिक स्वामी की स्थिति बढ़ाता है और स्वामी की सशर्त सामग्री बदलता है।- पुष्टि करें कि संपादक दिखाई देता रहता है, उसका टेक्स्ट
Sample note Betaबना रहता है और संशोधन डिस्प्ले आगे बढ़ता है। Doneपर क्लिक करें। पुष्टि करें कि विस्तारित लेआउट सक्रिय होने पर विंडो संपादित टेक्स्ट को विस्तारित लेआउट में दिखाती है।- संपादक फिर खोलें और पुष्टि करें कि संपादित टेक्स्ट उपलब्ध है।
अपडेट बटन शीट के अंदर है, ताकि परीक्षण अंतर्निहित विंडो पर क्लिक करने पर निर्भर न हो। AppKit शीट को दस्तावेज़-मोडल बताता है: शीट दिखाई देते समय, उसकी पैरेंट विंडो को निर्देशित अधिकांश इवेंट प्रतिबंधित होते हैं। बाइंडिंग के ज़रिए स्वामी को अपडेट करने से यह उदाहरण सीधे स्थिति परिवर्तन की जाँच कर पाता है। beginSheet(_:completionHandler:) देखें।
तय करें कि संपादक बंद होने का क्या अर्थ होना चाहिए
यह उदाहरण स्वामी के टेक्स्ट को तुरंत संपादित करता है। Done संपादक बंद करता है; यह अलग से सेव करने की कार्रवाई नहीं करता। स्ट्रिंग विंडो की स्थानीय स्थिति में रहती है और उदाहरण ऐप लॉन्च के बीच उसे सहेजता नहीं है। यह व्यवहार State में वर्णित साझा बाइंडिंग डिज़ाइन के अनुरूप है।
अगर आपके काम में रद्द किया जा सकने वाला ड्राफ़्ट चाहिए, तो अलग ड्राफ़्ट मान रखें और उसे दस्तावेज़ में केवल स्पष्ट पुष्टि कार्रवाई पर कॉपी करें। डिसमिस करने से पहले यह व्यवहार तय करें: ड्राफ़्ट लागू करना है या त्यागना, यह तय करना शीट का स्वामी कौन-सा दृश्य है, यह तय करने से अलग है।
तीन स्वतंत्र जाँचों से डिसमिस होने की वजह पता करें
अपने ऐप में नीचे दिया क्रम अपनाएँ। इससे यह मानकर चले बिना कि हर गायब होती शीट का कारण समान है, सामान्य पहचान नियमों को केंद्रित जाँच में बदला जा सकता है।
| जाँच | क्या देखें | व्यावहारिक सुधार |
|---|---|---|
| प्रस्तुति मान | हर वह लेखन जो बूलियन को false पर सेट करता है या वैकल्पिक प्रस्तुति आइटम को हटाता है |
डिसमिस करने वाले लेखन को जानबूझकर की गई बंद करने की कार्रवाइयों तक सीमित रखें |
| प्रस्तुतकर्ता की पहचान | सशर्त शाखाएँ, हटाई गई पंक्तियाँ, बदलते पूर्वज पहचानकर्ता | प्रस्तुति स्थिति और संशोधक—दोनों को किसी उपयुक्त स्थिर पूर्वज पर ले जाएँ |
| सामग्री का जीवनकाल | शीट-स्थानीय स्थिति, बदलते सामग्री पहचानकर्ता, संपादक सिंक्रोनाइज़ेशन | इच्छित संपादन सत्र बनाए रखें और मौजूदा सामग्री को सोच-समझकर अपडेट करें |
पहले, प्रस्तुति प्रॉपर्टी को असाइन करने और dismiss() को कॉल करने वाली जगहों के लिए अपने प्रोजेक्ट में खोजें। रीफ़्रेश कॉलबैक शीट को स्पष्ट रूप से बंद कर सकता है। उदाहरण की तरह, शीट के अपने दृश्य के अंदर dismiss पढ़ें: Apple दस्तावेज़ीकृत करता है कि यह कार्रवाई उस एनवायरनमेंट पर लागू होती है जहाँ से इसे लिया गया है। विंडो के रूट दृश्य में इसे पढ़ने पर वह विंडो को लक्ष्य बना सकती है। dismiss देखें।
दूसरे, संशोधक के ऊपर की दृश्य-श्रेणी की जाँच करें। यदि शीट ऐसे विवरण दृश्य से जुड़ी है जिसे रीफ़्रेश हटाता है, तो संशोधक को उस प्रतिस्थापन सीमा से ऊपर ले जाएँ। स्थानीय रूप से स्वामित्व वाली प्रस्तुति स्थिति को भी ऊपर ले जाएँ। Apple के दृश्य जीवनकाल के स्पष्टीकरण के अनुसार, जिस चाइल्ड की पहचान समाप्त होती है उसमें फ़्लैग रखने पर उसका स्टोरेज प्रतिस्थापन के प्रति संवेदनशील रहता है।
तीसरे, बंद हो चुकी प्रस्तुति और ऐसे संपादक में अंतर करें जो दिखाई तो देता रहता है, लेकिन अपना ड्राफ़्ट खो देता है। साधारण TextEditor उदाहरण से शुरू करें, फिर अपनी कस्टम सामग्री को चरणों में वापस जोड़ें। यह तुलना एक निदान विधि है: इससे पता लगाने में मदद मिलती है कि समस्या प्रस्तुति स्वामित्व से जुड़ी है या आपकी सामग्री अपडेट करने की लॉजिक से।
क्या आपको आइटम-आधारित शीट पर स्विच करना चाहिए?
जब कोई विशिष्ट चुनी गई इकाई प्रस्तुति का स्रोत हो, तो sheet(item:onDismiss:content:) का उपयोग करें। Apple एक वैकल्पिक Identifiable आइटम को दस्तावेज़ीकृत करता है, गैर-nil आइटम को कंटेंट क्लोज़र में पास करता है और आइटम बदलने पर प्रतिस्थापन का वर्णन करता है। ओवरलोड बदलने से अपने आप ऐसा प्रस्तुतकर्ता स्थिर नहीं रहता जिसका जीवनकाल समाप्त हो गया हो। आइटम-आधारित शीट देखें।
ऐसा पहचानकर्ता चुनें जो इच्छित संपादन सत्र के दौरान इकाई का प्रतिनिधित्व करे। Swift का Identifiable प्रोटोकॉल स्थिर पहचान व्यक्त करता है, और उसका दस्तावेज़ीकरण स्पष्ट रूप से आवश्यक अवधि और दायरा संबंधित प्रकारों पर छोड़ता है। हर बार कोई प्रॉपर्टी पढ़े जाने पर नया पहचानकर्ता देना किसी निरंतर इकाई का प्रतिनिधित्व नहीं कर सकता। Identifiable देखें।
डेमो जैसे सरल संपादक के लिए, बूलियन प्रस्तुति फ़्लैग और अलग टेक्स्ट बाइंडिंग इच्छित संबंध को समझना आसान बनाते हैं। चुने गए आइटम वाले संपादक के लिए, चयन की पहचान को अक्सर बदलने वाले फ़ील्ड से अलग रखें। किसी दूसरी इकाई का चयन जानबूझकर लिया गया प्रस्तुति निर्णय मानें और पहले तय करें कि मौजूदा ड्राफ़्ट के साथ क्या होना चाहिए।
क्या इंटरैक्टिव डिसमिसल बंद करने से शीट सक्रिय रहेगी?
interactiveDismissDisabled(_:) प्रोग्राम के अलावा होने वाले डिसमिसल को नियंत्रित करता है। Apple स्पष्ट रूप से कहता है कि यह प्रस्तुति बाइंडिंग बदलने या dismiss को कॉल करने से होने वाले डिसमिसल को नहीं रोकता। इसलिए इसकी दस्तावेज़ीकृत भूमिका पहचान प्रतिस्थापन का समाधान नहीं देती। interactiveDismissDisabled(_:) देखें।
यह संशोधक शीट की दृश्य-श्रेणी के अंदर तभी लगाएँ जब आपके इंटरफ़ेस को उस डिसमिसल व्यवहार की आवश्यकता हो, और स्पष्ट समापन पथ बनाए रखें। इस काम के लिए होस्ट और उसकी स्थिति को बनाए रखने से शुरुआत करें। कारण पहचानने से पहले डिसमिसल पर प्रतिबंध जोड़ने से मूल स्वामित्व समस्या अनसुलझी रह सकती है।
शीट में AppKit या TextKit सामग्री होने पर क्या बदलता है?
NSViewRepresentable के साथ एम्बेड किए गए NSTextView के लिए, निर्माण और अपडेट को अलग रखें। Apple makeNSView(context:) को निर्माण चरण और updateNSView(_:context:) को आगे की SwiftUI जानकारी लागू करने की जगह के रूप में परिभाषित करता है। कोऑर्डिनेटर डेलीगेट या टार्गेट-एक्शन बदलावों को वापस SwiftUI तक पहुँचाता है। NSViewRepresentable और makeNSView(context:) देखें।
इस जीवनचक्र से निकला एक उपयोगी कार्यान्वयन नियम यह है कि केवल असंबंधित स्वामी स्थिति बदलने पर संपादक को फिर से बनाने से बचें। उसकी सामग्री बदलने से पहले तय करें कि आने वाला मॉडल टेक्स्ट वास्तव में अलग है या नहीं और एक साथ होने वाले स्थानीय संपादनों को कैसे संभालना चाहिए। स्थिर शीट अपने आप टेक्स्ट पर प्रतिस्पर्धी लेखन का समाधान नहीं करती।
TextKit टेक्स्ट स्टोरेज, लेआउट और रेंडरिंग देता है। AppKit का NSTextView इन क्षमताओं को एक साथ रखता है और आधुनिक तथा लेगेसी लेआउट इंजन उपलब्ध कराता है। यह व्यवस्था संपादक की सामग्री से संबंधित है; प्रस्तुति स्वामित्व को फिर भी अपना स्थिर जीवनकाल चाहिए। संपादन कार्य के लिए आवश्यक होने पर TextKit का उपयोग करें और टेक्स्ट अपडेट व्यवहार की जाँच शीट डिसमिसल से अलग करें। Apple का TextKit परिचय देखें।
विंडो-स्वामित्व वाली AppKit प्रस्तुति कब उपयुक्त है?
यदि आपका मौजूदा ऐप पहले से ही AppKit में अपनी विंडो का जीवनचक्र संभालता है, तो macOS 26 उस विंडो पर सीधे SwiftUI सामग्री प्रस्तुत करने के लिए NSWindow.beginSheet(content:completionHandler:) लाता है। Apple शीट की dismiss एनवायरनमेंट कार्रवाई, आकार निर्धारण, टूलबार और इंटरैक्टिव डिसमिसल नियंत्रण के समर्थन का दस्तावेज़ीकरण करता है। इसे अपनाने से पहले macOS 26 SDK का उपयोग करें और macOS 26 की उपलब्धता सीमा लागू करें। beginSheet(content:completionHandler:) देखें।
लौटाया गया NSWindow.HostingSheetRepresentation प्रस्तुत मूल दृश्य बदल सकता है या AppKit से प्रोग्रामेटिक डिसमिसल का समर्थन कर सकता है। जब विंडो-स्तरीय स्वामित्व ऐप की संरचना के अनुकूल हो, तब यह दस्तावेज़ीकृत विकल्प देता है। ऊपर दिए गए स्थिर SwiftUI कंटेनर उदाहरण के लिए इसकी आवश्यकता नहीं है। NSWindow.HostingSheetRepresentation देखें।
macOS के पुराने संस्करणों के लिए, AppKit का मौजूदा beginSheet(_:completionHandler:) एक NSWindow शीट स्वीकार करता है और प्रस्तुति कतारबद्ध करने का दस्तावेज़ देता है। यह न मानें कि SwiftUI सामग्री वाला नया ओवरलोड उन सिस्टम पर उपलब्ध है। beginSheet(_:completionHandler:) देखें।
स्वामी को स्थिर रखें, प्रस्तुति मान सक्रिय रखें और संपादक के इच्छित सत्य-स्रोत को बनाए रखें। अधिक जटिल सामग्री वापस जोड़ने से पहले एक छोटे स्थानीय अपडेट ऐक्शन से इन शर्तों की पुष्टि करें। इससे Apple द्वारा दस्तावेज़ीकृत जीवनकाल और API सीमाओं के भीतर, इंटरफ़ेस अपडेट होते समय संपादन जारी रखने का ठोस तरीका मिलता है।
स्रोत
- 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