आप स्विफ्ट में व्यू कंट्रोलर और अन्य ऑब्जेक्ट के बीच डेटा कैसे साझा करते हैं?


88

कहो कि मेरे स्विफ्ट ऐप में कई व्यू कंट्रोलर हैं और मैं उनके बीच डेटा पास करने में सक्षम होना चाहता हूं। अगर मैं व्यू कंट्रोलर स्टैक में कई स्तर नीचे हूं, तो मैं डेटा को दूसरे व्यू कंट्रोलर को कैसे पास करूं? या टैब बार व्यू कंट्रोलर में टैब के बीच?

(ध्यान दें, यह प्रश्न एक "रिंगर" है।) यह इतना पूछा जाता है कि मैंने विषय पर एक ट्यूटोरियल लिखने का फैसला किया। नीचे मेरा जवाब देखें।


1
प्रतिनिधियों के लिए
गुगली करने की

4
मैंने इसे पोस्ट किया ताकि मैं इस सवाल के 10,000 उदाहरणों को हल प्रदान कर सकूं जो हर दिन यहां एसओ को दिखाते हैं। मेरा आत्म-उत्तर देखिए। :)
डंकन सी

क्षमा करें, मैं प्रतिक्रिया के साथ बहुत जल्दी था :) इस से लिंक करने में सक्षम होने के लिए अच्छा :)
milo526

2
कोई चिंता नहीं। आपने सोचा था कि मैं # 10,001, क्या आप नहीं थे? <grin>
डंकन सी

4
@DuncanC मुझे आपका उत्तर पसंद नहीं है। :( यह एक कैच के रूप में ठीक है, सभी परिदृश्यों का उत्तर ... इंसोमुचस, यह हर परिदृश्य के लिए काम करेगा , लेकिन यह भी लगभग किसी भी परिदृश्य के लिए सही दृष्टिकोण नहीं है। इसके बावजूद, अब हमने इसे अपने सिर में ले लिया है। इस विषय पर किसी भी प्रश्न को इस डुप्लिकेट के रूप में चिह्नित करना एक अच्छा विचार है? कृपया, नहीं।
nhgrif

जवाबों:


91

आपका प्रश्न बहुत व्यापक है। यह सुझाव देने के लिए कि प्रत्येक परिदृश्य का एक सरल कैच-ऑल्यूशन है, थोड़ा सा भोलापन है। तो, चलो इन कुछ परिदृश्यों से गुजरते हैं।


मेरे अनुभव में स्टैक ओवरफ्लो के बारे में पूछा जाने वाला सबसे आम परिदृश्य एक दृश्य नियंत्रक से अगले तक की सरल गुजरती जानकारी है।

यदि हम स्टोरीबोर्ड का उपयोग कर रहे हैं, तो हमारा पहला व्यू कंट्रोलर ओवरराइड कर सकता है prepareForSegue, जो वास्तव में यही है। UIStoryboardSegueइस पद्धति को कॉल करने पर एक ऑब्जेक्ट पास होता है, और इसमें हमारे गंतव्य दृश्य नियंत्रक का संदर्भ होता है। यहां, हम उन मानों को सेट कर सकते हैं जिन्हें हम पास करना चाहते हैं।

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "MySegueID" {
        if let destination = segue.destination as? SecondController {
            destination.myInformation = self.myInformation
        }
    }
}

वैकल्पिक रूप से, यदि हम स्टोरीबोर्ड का उपयोग नहीं कर रहे हैं, तो हम अपने दृश्य नियंत्रक को निब से लोड कर रहे हैं। हमारा कोड तब थोड़ा सरल है।

func showNextController() {
    let destination = SecondController(nibName: "SecondController", bundle: nil)
    destination.myInformation = self.myInformation
    show(destination, sender: self)
}

दोनों ही मामलों में, myInformationप्रत्येक व्यू कंट्रोलर पर एक संपत्ति होती है, जिसे एक व्यू कंट्रोलर से अगले तक डेटा को पास करने की आवश्यकता होती है। वे स्पष्ट रूप से प्रत्येक नियंत्रक पर समान नाम नहीं रखते हैं।


हम टैब के बीच जानकारी भी साझा करना चाहते हैं UITabBarController

इस मामले में, यह वास्तव में और भी सरल है।

सबसे पहले, एक उपवर्ग बनाएँ UITabBarController, और विभिन्न टैब के बीच हम जो भी जानकारी साझा करना चाहते हैं, उसके लिए यह गुण दें:

class MyCustomTabController: UITabBarController {
    var myInformation: [String: AnyObject]?
}

अब, यदि हम स्टोरीबोर्ड से अपना ऐप बना रहे हैं, तो हम बस अपने टैब बार कंट्रोलर की कक्षा को डिफ़ॉल्ट UITabBarControllerसे बदल सकते हैं MyCustomTabController। यदि हम एक स्टोरीबोर्ड का उपयोग नहीं कर रहे हैं, तो हम बस डिफ़ॉल्ट UITabBarControllerवर्ग के बजाय इस कस्टम वर्ग की एक आवृत्ति को इंस्टाल करते हैं और हमारे व्यू कंट्रोलर को इसमें जोड़ते हैं।

अब, टैब बार नियंत्रक के भीतर हमारे सभी व्यू कंट्रोलर इस संपत्ति को इस तरह एक्सेस कर सकते हैं:

if let tbc = self.tabBarController as? MyCustomTabController {
    // do something with tbc.myInformation
}

और UINavigationControllerउसी तरह से उपवर्ग करके , हम पूरे नेविगेशन स्टैक पर डेटा साझा करने के लिए समान दृष्टिकोण ले सकते हैं:

if let nc = self.navigationController as? MyCustomNavController {
    // do something with nc.myInformation
}

कई अन्य परिदृश्य हैं। किसी भी तरह से यह उत्तर उन सभी को कवर नहीं करता है।


1
मैं यह भी जोड़ना चाहता हूं कि कभी-कभी आप चाहते हैं कि कोई चैनल गंतव्य दृश्य नियंत्रक से स्रोत दृश्य नियंत्रक पर जानकारी वापस भेजें। उस स्थिति को संभालने का एक सामान्य तरीका गंतव्य के लिए एक प्रतिनिधि संपत्ति जोड़ना है, और फिर स्रोत दृश्य नियंत्रक की तैयारी में, गंतव्य दृश्य नियंत्रक के प्रतिनिधि संपत्ति को स्वयं पर सेट करें। (और एक प्रोटोकॉल को परिभाषित करता है जो संदेशों को परिभाषित करता है गंतव्य वीसी स्रोत वीसी को संदेश भेजने के लिए उपयोग करता है)
डंकन सी

1
nhgrif, मैं सहमत हूँ। नए डेवलपर्स के लिए सलाह यह होनी चाहिए कि यदि आपको स्टोरीबोर्ड पर दृश्यों के बीच डेटा पास करना है, तो उपयोग करें prepareForSegue। यह बहुत बुरा है कि यह बहुत ही सरल अवलोकन अन्य उत्तरों और खुदाई के बीच खो गया है।
रोब

2
@ रब यप। एकल और सूचनाएं अंतिम विकल्प होनी चाहिए। हमें लगभग हर परिदृश्‍य में सूचनाओं को प्राथमिकता prepareForSegueया अन्‍य प्रत्‍यक्ष स्‍थानान्‍तरण करना चाहिए और तब केवल नौसिखियों के साथ ठीक होना चाहिए जब वे उस परिदृश्‍य के साथ दिखें जिसके लिए ये स्थितियां काम नहीं करती हैं और हमें तब उन्‍हें इन अधिक वैश्विक दृष्टिकोणों के बारे में सिखाना होगा।
nhgrif

1
निर्भर करता है। लेकिन मैं बहुत, बहुत कोड के लिए हमारे डंपिंग ग्राउंड के रूप में अनुप्रयोग प्रतिनिधि का उपयोग करने के बारे में चिंतित हूँ हम नहीं जानते कि और कहाँ रखा जाए। यहाँ पागलपन का रास्ता निहित है।
nhgrif

2
@nhgrif। आपके उत्तर के लिए thx क्या होगा हालांकि आप चाहते हैं कि डेटा 4 या 5 व्यूकंट्रोलर्स के बीच पारित हो। अगर ive को क्लाइंट लॉगिन और पासवर्ड आदि का प्रबंधन करने वाले 4-5 व्यू कॉन्ट्रॉलर्स मिलते हैं और मैं इन व्यू कॉन्ट्रोलर्स के बीच उपयोगकर्ता का ईमेल पास करना चाहता हूं, तो क्या ऐसा करने का एक और सुविधाजनक तरीका है कि प्रत्येक व्यू कॉन्ट्रॉलर में var को घोषित करना और फिर उसे फॉरनसेग के भीतर पास करना। क्या एक ऐसा तरीका है जिसे मैं एक बार घोषित कर सकता हूं और प्रत्येक व्यू-कंट्रोलर इसे एक्सेस कर सकता है लेकिन एक तरह से यह अच्छा कोडिंग अभ्यास भी है?
लोजफ्लान

45

यह सवाल हर समय सामने आता है।

एक सुझाव एक डेटा कंटेनर सिंगलटन बनाने का है: एक वस्तु जो आपके एप्लिकेशन के जीवन में एक बार और केवल एक बार बनाई जाती है, और आपके ऐप के जीवन के लिए बनी रहती है।

यह दृष्टिकोण एक स्थिति के लिए अच्छी तरह से अनुकूल है जब आपके पास वैश्विक ऐप डेटा होता है जिसे आपके ऐप में विभिन्न वर्गों में उपलब्ध / संशोधित करने की आवश्यकता होती है।

व्यू कंट्रोलर्स के बीच वन-वे या 2-वे लिंक स्थापित करने जैसे अन्य दृष्टिकोण उन परिस्थितियों के लिए बेहतर हैं, जहां आप व्यू कंट्रोलर्स के बीच सीधे सूचना / संदेश भेज रहे हैं।

(अन्य विकल्पों के लिए नीचे nhgrif का उत्तर देखें।)

डेटा कंटेनर सिंगलटन के साथ, आप अपनी क्लास में एक प्रॉपर्टी जोड़ते हैं जो आपके सिंगलटन के लिए एक संदर्भ स्टोर करती है, और फिर उस प्रॉपर्टी को कभी भी उपयोग करने की आवश्यकता होती है।

आप अपना सिंगलटन सेट कर सकते हैं ताकि यह डिस्क पर सामग्री को सहेजे ताकि आपकी ऐप स्थिति लॉन्च के बीच बनी रहे।

मैंने GitHub पर एक डेमो प्रोजेक्ट बनाया, जिसमें दिखाया गया है कि आप यह कैसे कर सकते हैं। लिंक यहां दिया गया है:

GitHub पर SwiftDataContainerSingleton परियोजना यहां उस परियोजना से README है:

SwiftDataContainerSingleton

एप्लिकेशन स्टेट को बचाने और ऑब्जेक्ट्स के बीच साझा करने के लिए डेटा कंटेनर सिंगलटन का उपयोग करने का प्रदर्शन।

DataContainerSingletonवर्ग वास्तविक सिंगलटन है।

यह sharedDataContainerसिंगलटन के संदर्भ को बचाने के लिए एक स्थिर स्थिरांक का उपयोग करता है ।

सिंगलटन तक पहुंचने के लिए, सिंटैक्स का उपयोग करें

DataContainerSingleton.sharedDataContainer

नमूना परियोजना डेटा कंटेनर में 3 गुणों को परिभाषित करती है:

  var someString: String?
  var someOtherString: String?
  var someInt: Int?

someIntडेटा कंटेनर से संपत्ति लोड करने के लिए , आप इस तरह कोड का उपयोग करेंगे:

let theInt = DataContainerSingleton.sharedDataContainer.someInt

कुछ मान को सहेजने के लिए, आप सिंटैक्स का उपयोग करेंगे:

DataContainerSingleton.sharedDataContainer.someInt = 3

DataContainerSingleton की initविधि के लिए एक पर्यवेक्षक जोड़ता है UIApplicationDidEnterBackgroundNotification। यह कोड इस तरह दिखता है:

goToBackgroundObserver = NSNotificationCenter.defaultCenter().addObserverForName(
  UIApplicationDidEnterBackgroundNotification,
  object: nil,
  queue: nil)
  {
    (note: NSNotification!) -> Void in
    let defaults = NSUserDefaults.standardUserDefaults()
    //-----------------------------------------------------------------------------
    //This code saves the singleton's properties to NSUserDefaults.
    //edit this code to save your custom properties
    defaults.setObject( self.someString, forKey: DefaultsKeys.someString)
    defaults.setObject( self.someOtherString, forKey: DefaultsKeys.someOtherString)
    defaults.setObject( self.someInt, forKey: DefaultsKeys.someInt)
    //-----------------------------------------------------------------------------

    //Tell NSUserDefaults to save to disk now.
    defaults.synchronize()
}

प्रेक्षक कोड में यह डेटा कंटेनर के गुणों को बचाता है NSUserDefaults। आप NSCodingराज्य डेटा को बचाने के लिए कोर डेटा, या अन्य विभिन्न तरीकों का भी उपयोग कर सकते हैं ।

DataContainerSingleton की initविधि इसके गुणों के लिए सहेजे गए मानों को लोड करने का भी प्रयास करती है।

Init विधि का वह भाग इस तरह दिखता है:

let defaults = NSUserDefaults.standardUserDefaults()
//-----------------------------------------------------------------------------
//This code reads the singleton's properties from NSUserDefaults.
//edit this code to load your custom properties
someString = defaults.objectForKey(DefaultsKeys.someString) as! String?
someOtherString = defaults.objectForKey(DefaultsKeys.someOtherString) as! String?
someInt = defaults.objectForKey(DefaultsKeys.someInt) as! Int?
//-----------------------------------------------------------------------------

NSUserDefaults में मानों को लोड करने और सहेजने की कुंजी को स्ट्रिंग स्थिरांक के रूप में संग्रहीत किया जाता है DefaultsKeys, जो एक संरचना का हिस्सा है , जिसे इस प्रकार परिभाषित किया गया है:

struct DefaultsKeys
{
  static let someString  = "someString"
  static let someOtherString  = "someOtherString"
  static let someInt  = "someInt"
}

आप इस तरह के एक स्थिरांक का संदर्भ देते हैं:

DefaultsKeys.someInt

डेटा कंटेनर सिंगलटन का उपयोग करना:

यह नमूना अनुप्रयोग डेटा कंटेनर सिंगलटन का सही उपयोग करता है।

दो दृश्य नियंत्रक हैं। पहला UIViewController का एक कस्टम उपवर्ग है ViewController, और दूसरा UIViewController का एक कस्टम उपवर्ग है SecondVC

दोनों दृश्य नियंत्रकों का उन पर एक पाठ क्षेत्र है, और दोनों डेटा कंटेनर सिंगलटन की someIntसंपत्ति से अपनी viewWillAppearविधि में पाठ क्षेत्र में एक मूल्य लोड करते हैं , और दोनों पाठ फ़ील्ड से वर्तमान मान को डेटा कंटेनर के `someInt 'में वापस सहेजते हैं।

पाठ फ़ील्ड में मान को लोड करने का कोड viewWillAppear:विधि में है:

override func viewWillAppear(animated: Bool)
{
  //Load the value "someInt" from our shared ata container singleton
  let value = DataContainerSingleton.sharedDataContainer.someInt ?? 0
  
  //Install the value into the text field.
  textField.text =  "\(value)"
}

डेटा-कंटेनर में उपयोगकर्ता-संपादित मान को सहेजने का कोड दृश्य नियंत्रकों के textFieldShouldEndEditingतरीकों में है:

 func textFieldShouldEndEditing(textField: UITextField) -> Bool
 {
   //Save the changed value back to our data container singleton
   DataContainerSingleton.sharedDataContainer.someInt = textField.text!.toInt()
   return true
 }

आपको viewDillLoad के बजाय viewWillAppear में अपने उपयोगकर्ता इंटरफ़ेस में मान लोड करना चाहिए ताकि आपके UI को हर बार व्यू कंट्रोलर प्रदर्शित हो।


8
मैं इसे डाउन-वोट नहीं करना चाहता क्योंकि मुझे लगता है कि यह उत्कृष्ट है कि आपने संसाधन के रूप में सवाल और जवाब बनाने के लिए समय का निवेश किया। धन्यवाद। इसके बावजूद, मुझे लगता है कि हम मॉडल ऑब्जेक्ट्स के लिए सिंगलटन की वकालत करने के लिए नए डेवलपर्स के लिए एक महान कार्य करते हैं। मैं "सिंगलटन बुराई कर रहा हूं" शिविर में नहीं है (हालांकि नॉब्स को Google को वाक्यांशों को बेहतर ढंग से सराहना करने के लिए कहना चाहिए), लेकिन मुझे लगता है कि मॉडल डेटा एकल का एक संदिग्ध / बहस योग्य उपयोग है।
रोब

2-तरह के लिंक के बारे में एक शानदार लिखना देखना पसंद करेंगे
Cmag

@ डंकन सी हैलो डंकन मैं प्रत्येक मॉडल में स्टेटिक ऑब्जेक्ट बना रहा हूं इसलिए मुझे किसी से डेटा मिलता है जहां यह सही दृष्टिकोण है या मुझे आपके पथ कारण का पालन करना होगा यह बहुत सही लगता है।
वीरेंद्र सिंह राठौर

@ वीरेंद्रसिंह राठौर, ग्लोबल स्टैटिक वैरिएबल ऐप में डेटा साझा करने का सबसे खराब तरीका है। वे कसकर आपके ऐप के हिस्सों को एक साथ जोड़ते हैं और गंभीर निर्भरता का परिचय देते हैं। यह "बहुत सही" के ठीक विपरीत है।
डंकन सी

@ डंकन - क्या यह पैटर्न एक करंट ऑब्जेक्ट के लिए काम करेगा - मूल रूप से एक एकल उपयोगकर्ता जो आपके ऐप में लॉग इन है? thx
टाइमपोन

9

स्विफ्ट 4

स्विफ्ट में डेटा पास करने के लिए बहुत सारे दृष्टिकोण हैं। यहाँ मैं इसके कुछ बेहतरीन तरीकों को जोड़ रहा हूँ।

1) StoryBoard Segue का उपयोग करना

सोर्स और डेस्टिनेशन व्यू कंट्रोलर्स के बीच डेटा पास करने के लिए स्टोरीबोर्ड सेगमेंट बहुत उपयोगी हैं और इसके विपरीत भी।

// If you want to pass data from ViewControllerB to ViewControllerA while user tap on back button of ViewControllerB.
        @IBAction func unWindSeague (_ sender : UIStoryboardSegue) {
            if sender.source is ViewControllerB  {
                if let _ = sender.source as? ViewControllerB {
                    self.textLabel.text = "Came from B = B->A , B exited"
                }
            }
        }

// If you want to send data from ViewControllerA to ViewControllerB
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if  segue.destination is ViewControllerB {
                if let vc = segue.destination as? ViewControllerB {
                    vc.dataStr = "Comming from A View Controller"
                }
            }
        }

2) प्रतिनिधि विधियों का उपयोग करना

ViewControllerD

//Make the Delegate protocol in Child View Controller (Make the protocol in Class from You want to Send Data)
    protocol  SendDataFromDelegate {
        func sendData(data : String)
    }

    import UIKit

    class ViewControllerD: UIViewController {

        @IBOutlet weak var textLabelD: UILabel!

        var delegate : SendDataFromDelegate?  //Create Delegate Variable for Registering it to pass the data

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            textLabelD.text = "Child View Controller"
        }

        @IBAction func btnDismissTapped (_ sender : UIButton) {
            textLabelD.text = "Data Sent Successfully to View Controller C using Delegate Approach"
            self.delegate?.sendData(data:textLabelD.text! )
            _ = self.dismiss(animated: true, completion:nil)
        }
    }

ViewControllerC

    import UIKit

    class ViewControllerC: UIViewController , SendDataFromDelegate {

        @IBOutlet weak var textLabelC: UILabel!

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }

        @IBAction func btnPushToViewControllerDTapped( _ sender : UIButton) {
            if let vcD = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerD") as?  ViewControllerD  {
                vcD.delegate = self // Registring Delegate (When View Conteoller D gets Dismiss It can call sendData method
    //            vcD.textLabelD.text = "This is Data Passing by Referenceing View Controller D Text Label." //Data Passing Between View Controllers using Data Passing
                self.present(vcD, animated: true, completion: nil)
            }
        }

        //This Method will called when when viewcontrollerD will dismiss. (You can also say it is a implementation of Protocol Method)
        func sendData(data: String) {
            self.textLabelC.text = data
        }

    }

गोगलर्स के लिए जो पूरी तरह से और पूरी तरह से खो गए हैं, जहां स्टैकऑवरफ्लो उत्तर डालना है 'स्विफ्ट कोड स्निपेट्स जैसा कि मैं हूं, जैसा कि यह माना जाता है कि आपको हमेशा पता होना चाहिए कि वे कोड कहां जाते हैं: मैंने विकल्प 1 का उपयोग किया) से भेजने के ViewControllerAलिए ViewControllerB। मैंने अपने पिछले भाग में कोड स्निपेट ViewControllerA.swift(जहां ViewControllerA.swiftवास्तव में जो कुछ भी आपकी फ़ाइल का नाम है, बिल्कुल) को अंतिम घुंघराले ब्रेस से ठीक पहले चिपका दिया। " prepare" वास्तव में एक दिए गए वर्ग [जो कुछ भी नहीं करता है] में एक विशेष रूप से निर्मित पूर्व-विद्यमान फ़ंक्शन है, यही कारण है कि आपको overrideइसे " " करना है
वेल्कून

8

एक अन्य विकल्प अधिसूचना केंद्र (NSNotificationCenter) और पोस्ट नोटिफिकेशन का उपयोग करना है। यह एक बहुत ढीली युग्मन है। एक अधिसूचना के प्रेषक को यह जानने या देखभाल करने की आवश्यकता नहीं है कि कौन सुन रहा है। यह सिर्फ एक अधिसूचना पोस्ट करता है और इसके बारे में भूल जाता है।

सूचनाएं एक-से-कई संदेश पास करने के लिए अच्छी हैं, क्योंकि किसी दिए गए संदेश को सुनने वाले पर्यवेक्षकों की एक मनमानी संख्या हो सकती है।


2
ध्यान दें कि सूचना केंद्र का उपयोग करने से कपलिंग का परिचय होता है जो शायद बहुत ढीला है। यह आपके कार्यक्रम के प्रवाह को बहुत मुश्किल बना सकता है, इसलिए इसका उपयोग सावधानी से किया जाना चाहिए।
डंकन सी

2

एक डेटा कंट्रोलर सिंगलटन बनाने के बजाय मैं एक डेटा कंट्रोलर इंस्टेंस बनाने और उसे पास करने का सुझाव दूंगा। निर्भरता इंजेक्शन का समर्थन करने के लिए मैं पहले एक DataControllerप्रोटोकॉल बनाऊंगा:

protocol DataController {
    var someInt : Int {get set} 
    var someString : String {get set}
}

तब मैं एक SpecificDataController(या जो भी नाम वर्तमान में उपयुक्त होगा) वर्ग बनाऊंगा:

class SpecificDataController : DataController {
   var someInt : Int = 5
   var someString : String = "Hello data" 
}

तब ViewControllerवर्ग के पास एक क्षेत्र होना चाहिए dataController। ध्यान दें कि dataControllerप्रोटोकॉल का प्रकार है DataController। इस तरह से डेटा कंट्रोलर कार्यान्वयन को स्विच करना आसान है:

class ViewController : UIViewController {
   var dataController : DataController?
   ...
}

में AppDelegateहम ViewController के सेट कर सकते हैं dataController:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    if let viewController = self.window?.rootViewController as? ViewController {
        viewController.dataController =  SpecificDataController()
    }   
    return true
}

जब हम एक अलग दृष्टिकोण dataControllerपर जाते हैं, तो हम उस पर से गुजर सकते हैं :

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    ...   
}

अब जब हम एक अलग कार्य के लिए डेटा कंट्रोलर को स्विच करना चाहते हैं तो हम ऐसा कर सकते हैं AppDelegateऔर डेटा कंट्रोलर का उपयोग करने वाले किसी अन्य कोड को बदलना नहीं है।

यह निश्चित रूप से ओवरकिल है अगर हम बस एक ही मूल्य के आसपास से गुजरना चाहते हैं। इस मामले में nhgrif के उत्तर के साथ जाना सबसे अच्छा है।

इस दृष्टिकोण के साथ हम अलग-अलग दृश्य बना सकते हैं तर्क भाग।


1
नमस्कार, यह दृष्टिकोण स्वच्छ, परीक्षण योग्य है, और मैं ज्यादातर समय छोटे अनुप्रयोगों में उपयोग करता हूं, लेकिन बड़े लोगों में, जहां हर वीसी नहीं (शायद रूट वीसी भी नहीं) को निर्भरता की आवश्यकता हो सकती है (उदाहरण के लिए इस मामले में DataController) प्रत्येक वीसी के लिए निर्भरता की आवश्यकता होती है, ताकि वह उसे पूरा कर सके। इसके अलावा, यदि आप विभिन्न प्रकार के वीसी का उपयोग करते हैं (जैसे कि नियमित यूआईवीसी बनाम नेवीवीवीसी) तो आपको उन निर्भरता चर को जोड़ने के लिए उन विभिन्न प्रकारों को उप-वर्ग करना होगा। आप यह कैसे कर सकते हैं?
रॉबर्टो क्यूबा

1

जैसा कि @nhgrif ने अपने उत्कृष्ट उत्तर में बताया, कुलपति (देखने वाले नियंत्रक) और अन्य वस्तुएं एक-दूसरे के साथ संवाद कर सकती हैं, बहुत सारे तरीके हैं।

मेरे पहले उत्तर में उल्लिखित डेटा सिंगलटन वास्तव में सीधे संवाद करने की तुलना में वैश्विक स्थिति को साझा करने और बचाने के बारे में अधिक है।

nhrif का उत्तर आपको स्रोत से गंतव्य वीसी तक सीधे सूचना भेजने की सुविधा देता है। जैसा कि मैंने उत्तर में उल्लेख किया है, गंतव्य से स्रोत तक संदेश वापस भेजना भी संभव है।

वास्तव में, आप विभिन्न दृश्य नियंत्रकों के बीच एक सक्रिय एक-तरफ़ा या 2-तरफ़ा चैनल सेट कर सकते हैं। यदि व्यू कंट्रोलर एक स्टोरीबोर्ड सेग के माध्यम से जुड़े हुए हैं, तो लिंक सेट करने का समय तैयार करने वाले सेग विधि में है।

मेरे पास जीथब पर एक नमूना परियोजना है जो बच्चों के रूप में 2 अलग-अलग टेबल व्यू की मेजबानी करने के लिए एक पैरेंट व्यू कंट्रोलर का उपयोग करती है। चाइल्ड व्यू कंट्रोलर्स एंबेड सेगमेंट का उपयोग करके लिंक किए जाते हैं, और पेरेंट व्यू कंट्रोलर तैयार करते समय प्रत्येक व्यू कंट्रोलर के साथ 2-वे लिंक को जोड़ते हैं।

आप उस प्रोजेक्ट को जीथब (लिंक) पर पा सकते हैं । हालाँकि, मैंने इसे ऑब्जेक्टिव-सी में लिखा है, और इसे स्विफ्ट में नहीं बदला है, इसलिए यदि आप ऑब्जेक्टिव-सी में सहज नहीं हैं, तो इसे फॉलो करना थोड़ा मुश्किल हो सकता है


1

स्विफ्ट 3:

यदि आपके पास पहचाने गए सेगमेंट उपयोग के साथ एक स्टोरीबोर्ड है:

func prepare(for segue: UIStoryboardSegue, sender: Any?)

यद्यपि यदि आप विभिन्न UIViewControllers के बीच नेविगेशन सहित प्रोग्रामिक रूप से सब कुछ करते हैं तो विधि का उपयोग करें:

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool)

नोट: दूसरे तरीके का उपयोग करने के लिए आपको अपना UINavigationController बनाने की आवश्यकता है, आप UIViewControllers को, एक प्रतिनिधि को आगे बढ़ा रहे हैं और इसे प्रोटोकॉल UINavigationControllerDelegate के अनुरूप करने की आवश्यकता है:

   class MyNavigationController: UINavigationController, UINavigationControllerDelegate {

    override func viewDidLoad() {
        self.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {

     // do what ever you need before going to the next UIViewController or back
     //this method will be always called when you are pushing or popping the ViewController

    }
}

सेल्फ डेलीगेट कभी न करें। स्व
मल्हल

1

यह निर्भर करता है कि आप कब डेटा प्राप्त करना चाहते हैं।

यदि आप जब चाहें डेटा प्राप्त करना चाहते हैं, एक सिंगलटन पैटर्न का उपयोग कर सकते हैं। ऐप रनटाइम के दौरान पैटर्न क्लास सक्रिय है। यहाँ सिंगलटन पैटर्न का एक उदाहरण है।

class AppSession: NSObject {

    static let shared = SessionManager()
    var username = "Duncan"
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        print(AppSession.shared.username)
    }
}

यदि आप किसी कार्रवाई के बाद डेटा प्राप्त करना चाहते हैं, तो NotificationCenter का उपयोग कर सकते हैं।

extension Notification.Name {
    static let loggedOut = Notification.Name("loggedOut")
}

@IBAction func logoutAction(_ sender: Any) {
    NotificationCenter.default.post(name: .loggedOut, object: nil)
}

NotificationCenter.default.addObserver(forName: .loggedOut, object: nil, queue: OperationQueue.main) { (notify) in
    print("User logged out")
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.