wake-up-neo.com

Zugriff auf Container View Controller von übergeordnetem iOS

in iOS6 ist mir die neue Containeransicht aufgefallen, aber ich bin nicht ganz sicher, wie sie aus der übergeordneten Ansicht auf den Controller zugreifen kann.

Szenario:

example

Ich möchte auf die Beschriftungen im Alert-Ansichts-Controller von dem View-Controller zugreifen, der die Containeransicht enthält.

Es gibt einen Unterschied zwischen ihnen, kann ich das verwenden?

186
Adam Waite

Ja, Sie können das Segment verwenden, um Zugriff auf den untergeordneten Ansichtscontroller (und dessen Ansicht und Unteransichten) zu erhalten. Geben Sie dem Segment einen Bezeichner (z. B. alertview_embed), indem Sie den Inspektor Attribute in Storyboard verwenden. Lassen Sie dann den übergeordneten Ansichtscontroller (der die Containeransicht enthält) eine Methode wie folgt implementieren:

- (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...
   }
}
348
Peter E

Sie können dies einfach mit self.childViewControllers.lastObject tun (vorausgesetzt, Sie haben nur ein Kind, andernfalls verwenden Sie objectAtIndex:). 

50
rdelmar

für die schnelle Programmierung

du kannst so schreiben

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
    }
}
23
Sruit A.Suk

Die prepareForSegue-Methode funktioniert zwar, hängt jedoch von der magischen Zeichenfolge der Segmentkennung ab. Vielleicht gibt es einen besseren Weg.

Wenn Sie die Klasse der VC kennen, die Sie suchen, können Sie dies mit einer berechneten Eigenschaft sehr ordentlich tun:

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

Dies beruht auf childViewControllers. Ich bin zwar einig, dass es anfällig sein könnte, sich auf die erste zu verlassen, die Benennung der von Ihnen gesuchten Klasse lässt dies jedoch recht solide erscheinen.

15
SimplGy

Eine aktualisierte Antwort für Swift 3 unter Verwendung einer berechneten Eigenschaft:

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

Dadurch wird nur die Liste der Kinder durchlaufen, bis die erste Übereinstimmung erreicht ist.

9
Robin Daugherty

self.childViewControllers ist relevanter, wenn Sie die Kontrolle vom übergeordneten Element benötigen. Wenn der untergeordnete Controller beispielsweise eine Tabellensicht ist und Sie ihn zwangsweise erneut laden oder eine Eigenschaft über ein Tastenfeld oder ein anderes Ereignis auf dem übergeordneten View-Controller ändern möchten, können Sie dies tun, indem Sie auf die Instanz von ChildViewController und nicht über preparForSegue zugreifen. Beide haben unterschiedliche Anwendungen.

8
Gautam Jain

Falls jemand nach Swift 3.0 sucht,

viewController1 , viewController2 und so weiter sind dann verfügbar.

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
Marco Leong

Mit Generic können Sie einige süße Dinge tun. Hier ist eine Erweiterung zu Array:

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

Sie können dies dann in Ihrem viewController tun:

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

Es gibt eine andere Möglichkeit, die switch-Anweisung von Swift für den Typ des View-Controllers zu verwenden:

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
Joanna Carter

Ich benutze Code wie:

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

du kannst so schreiben

- (IBAction)showDetail:(UIButton *)sender {  
            DetailViewController *detailVc = [self.childViewControllers firstObject];  
        detailVc.lable.text = sender.titleLabel.text;  
    }  
}
0
Khurshid