अभिभावक iOS से एक्सेस कंटेनर व्यू कंट्रोलर देखें


203

iOS6 में मैंने नया कंटेनर व्यू देखा लेकिन मुझे यकीन नहीं है कि यह कंट्रोलर को कैसे एक्सेस कर सकता है।

परिदृश्य:

उदाहरण

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

उनके बीच एक बहस है, क्या मैं इसका इस्तेमाल कर सकता हूं?


आधुनिक कंटेनर दृश्यों के लिए पूरी तरह से यहां बताया गया है: stackoverflow.com/a/23403979/294884
फेटी

जवाबों:


362

हां, आप चाइल्ड व्यू कंट्रोलर (और इसके दृश्य और साक्षात्कार) तक पहुंचने के लिए सेग का उपयोग कर सकते हैं। alertview_embedस्टोरीबोर्ड में एट्रिब्यूट्स इंस्पेक्टर का उपयोग करके, एक पहचानकर्ता (जैसे ) को तर्क दें। फिर मूल दृश्य नियंत्रक (एक आवास कंटेनर दृश्य) इस तरह से एक विधि को लागू करें:

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
   NSString * segueName = segue.identifier;
   if ([segueName isEqualToString: @"alertview_embed"]) {
       AlertViewController * childViewController = (AlertViewController *) [segue destinationViewController];
       AlertView * alertView = childViewController.view;
       // do something with the AlertView's subviews here...
   }
}

1
हम बहस नहीं कर रहे हैं? क्या मुझसे कोई चूक हो रही है...?
एडम वेट 23

25
हां, एक एंबेड सीग है जो तब होता है जब दूसरे व्यू कंट्रोलर को पहले व्यू कंट्रोलर का बच्चा बनाया जाता है। readyForSegue: ऐसा होने से ठीक पहले कहा जाता है। आप इस अवसर का उपयोग बच्चे को डेटा पास करने के लिए, या बाद में उपयोग के लिए बच्चे के लिए एक संदर्भ स्टोर करने के लिए कर सकते हैं। डेवलपर को
पीटर ई

1
आह ठीक है, जब दृश्य लोड होता है, तो क्या 'दूसरे दृश्य नियंत्रक को पहले दृश्य नियंत्रक का बच्चा बनाया जाता है'? यह अब अधिक समझ में आ रहा है, धन्यवाद। मैं अभी अपने प्रोजेक्ट के साथ नहीं हूं, लेकिन बाद में परीक्षण करूंगा
एडम वेट

1
वास्तव में, यह viewDidLoad से पहले कहा जाता है। जब तक ViewDidLoad तक पहुंचा जाता है, तब तक माता-पिता और बच्चे कनेक्ट हो चुके होते हैं और माता-पिता में [self childViewControllers] सभी चाइल्ड कंट्रोलर्स की एक सरणी वापस कर देंगे (देखें rdelmar का जवाब नीचे देखें)।
पीटर ई

2
मैं प्रस्तावित समाधान में एक चेतावनी जोड़ दूंगा: बच्चे (गंतव्य) के दृश्य व्यू नियंत्रक की संपत्ति तक पहुंचते समय बहुत सावधान रहें: कुछ परिस्थितियों में यह इसके व्यूडीडलड को वहां बुलाया जाएगा और फिर मैं किसी भी जरूरी सेगमेंट डेटा को स्थापित करने की सिफारिश करूंगा। ताकि viewDidLoad सुरक्षित रूप से आग लगा सके।
AlwaysLearning

56

आप ऐसा कर सकते हैं self.childViewControllers.lastObject(केवल यह मानते हुए कि आपके पास केवल एक बच्चा है, अन्यथा उपयोग करें objectAtIndex:)।


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

2
@ फ़ायडो, और 'सेगमेंट की तैयारी' पर कई कंटेनरों को संभालने में क्या समस्या है?
गोनज़ेलेज़

1
क्या हुआ अगर (भयावह!) आप स्टोरीबोर्ड से स्विच करने का निर्णय लेते हैं या अनुक्रम का उपयोग नहीं करते हैं, आदि तो आपको कोड बनाने के लिए खुदाई करना होगा, आदि
टॉम एंडरसन

2
यह मेरा सामान्य दृष्टिकोण है, लेकिन यह अब मेरे लिए दुर्घटनाग्रस्त हो गया है क्योंकि मैं childViewControllers"बहुत जल्द" का उपयोग कर रहा हूं
माजिद

24

स्विफ्ट प्रोग्रामिंग के लिए

आप इस तरह लिख सकते हैं

var containerViewController: ExampleViewController?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // you can set this name in 'segue.embed' in storyboard
    if segue.identifier == "checkinPopupIdentifierInStoryBoard" {
        let connectContainerViewController = segue.destinationViewController as ExampleViewController
        containerViewController = connectContainerViewController
    }
}

If स्टेटमेंट पर segueName के बाद प्रश्न चिह्न के लिए क्या उपयोग है? "अगर सेगनेम?"
22

18

prepareForSegueदृष्टिकोण से काम करता है, लेकिन यह segue पहचानकर्ता जादू स्ट्रिंग पर निर्भर करता है। शायद एक बेहतर तरीका है।

यदि आपको पता है कि वीसी की कक्षा आपके बाद की है, तो आप यह गणना संपत्ति के साथ बड़े करीने से कर सकते हैं:

var camperVan: CamperVanViewController? {
  return childViewControllers.flatMap({ $0 as? CamperVanViewController }).first
  // This works because `flatMap` removes nils
}

यह निर्भर करता है childViewControllers। जबकि मैं मानता हूं कि यह पहले एक पर भरोसा करने के लिए नाजुक हो सकता है, आप जिस वर्ग की तलाश कर रहे हैं उसका नामकरण यह काफी ठोस प्रतीत होता है।


3
return childViewControllers.filter { $0 is CamperVanViewController }.firstएक लाइनर में
एडम वेट

1
मैंने तब से किया है, childViewControllers.flatMap({ $0 as? CamperVanViewController }).firstजो मुझे लगता है कि यह थोड़ा बेहतर है, क्योंकि यह किसी भी नेल्स को काटता है और छुटकारा दिलाता है।
सिंपलजी

यह एक अच्छा समाधान है यदि आप उस व्यू कंट्रोलर को एक से अधिक बार एक्सेस करना चाहते हैं
गेब्रियल गोंकाल्वेस

यह निराशाजनक है - कोई विशेष कारण नहीं है कि आपके पास उस विशेष वर्ग में से केवल एक हो सकता है। यही कारण है कि पहचानकर्ता मौजूद हैं। बस मानक सूत्र का पालन करें ... stackoverflow.com/a/23403979/294884
फेटी

केवल पहला तत्व लेने के लिए फ़िल्टर न करें। बस उपयोग करें first(where:)childViewControllers.first(where: { $0 is CamperVanViewController })
अलेक्जेंडर -

9

एक संगणित संपत्ति का उपयोग करके स्विफ्ट 3 के लिए एक अद्यतन जवाब:

var jobSummaryViewController: JobSummaryViewController {
    get {
        let ctrl = childViewControllers.first(where: { $0 is JobSummaryViewController })
        return ctrl as! JobSummaryViewController
    }
}

यह केवल बच्चों की सूची को तब तक प्रसारित करता है जब तक कि यह पहले मैच तक नहीं पहुंच जाता।


8

self.childViewControllers माता-पिता से नियंत्रण की आवश्यकता होने पर अधिक प्रासंगिक है। उदाहरण के लिए, यदि चाइल्ड कंट्रोलर एक टेबल व्यू है और आप इसे जबरदस्ती फिर से लोड करना चाहते हैं या बटन टैप या पेरेंट व्यू कंट्रोलर के किसी अन्य ईवेंट के जरिए प्रॉपर्टी बदलना चाहते हैं, तो आप चाइल्डव्यूकंट्रोलर के इंस्टेंस पर पहुंचकर कर सकते हैं, न कि तैयारीफ्रीग्यूजर के जरिए। दोनों के आवेदन अलग-अलग तरीके से हैं।


2

दृश्य नियंत्रक के प्रकार पर स्विफ्ट के स्विच स्टेटमेंट का उपयोग करने का एक और तरीका है:

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
  switch segue.destination
  {
    case let aViewController as AViewController:
      self.aViewController = aViewController
    case let bViewController as BViewController:
      self.bViewController = bViewController
    default:
      return
  }
}

1

मैं जैसे कोड का उपयोग करता हूं:

- (IBAction)showCartItems:(id)sender{ 
  ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
  [self addChildViewController:listOfItemsVC];
 }

1

मामले में किसी को स्विफ्ट 3.0 की तलाश है ,

viewController1 , viewController2 और इतने पर तो सुलभ हो जाएगा।

let viewController1 : OneViewController!
let viewController2 : TwoViewController!

// Safety handling of optional String
if let identifier: String = segue.identifier {

    switch identifier {

    case "segueName1":
        viewController1 = segue.destination as! OneViewController
        break

    case "segueName2":
        viewController2 = segue.destination as! TwoViewController
        break

    // ... More cases can be inserted here ...

    default:
        // A new segue is added in the storyboard but not yet including in this switch
        print("A case missing for segue identifier: \(identifier)")
        break
    }

} else {
    // Either the segue or the identifier is inaccessible 
    print("WARNING: identifier in segue is not accessible")
}

1

जेनेरिक के साथ आप कुछ मीठी बातें कर सकते हैं। यहाँ ऐरे का विस्तार है:

extension Array {
    func firstMatchingType<Type>() -> Type? {
        return first(where: { $0 is Type }) as? Type
    }
}

फिर आप अपने दृश्य में यह कर सकते हैंकंट्रोलर:

var viewControllerInContainer: YourViewControllerClass? {
    return childViewControllers.firstMatchingType()!
}

0

आप इस तरह लिख सकते हैं

- (IBAction)showDetail:(UIButton *)sender {  
            DetailViewController *detailVc = [self.childViewControllers firstObject];  
        detailVc.lable.text = sender.titleLabel.text;  
    }  
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.