I\'m coming from as AS3 background so it might be easier for me to show you what I\'m trying to do with AS3. I have a UIViewController(root) and inside that I have a ContainerV
Well or you can use static variables, which is probably the most straightforward way.
class ParentViewController: UIViewController {
static var instance:ParentViewController?
override func awakeFromNib() {
self.dynamicType.instance = self
}
func parentFunction() {
print("called \(#function) in \(self.dynamicType)")
}
}
class ChildViewController: UIViewController {
func childFunction() {
ParentViewController.instance?.parentFunction()
}
override func viewDidAppear(_ animated: Bool) {
childFunction()
}
}
There are two ways:
1) Use a delegate protocol (recommended)
a) In your child, create a delegate protocol, and an optional property on the child VC that will hold the delegate.
protocol ChildViewControllerDelegate {
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
}
b) In the delegate protocol create a method that will be called when the button was pressed, and implement a buttonWasPressed()
method in the child that calls this method on the delegate. (You'll want to connect this method up with a button in the storyboard)
protocol ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController:ChildViewController)
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
@IBOutlet weak var button: UIButton!
@IBAction func buttonWasPressed(sender: AnyObject) {
self.delegate?.childViewControllerDidPressButton(self)
}
}
c) Make your parent view controller conform to the child protocol
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
c) When the child is embedded in the parent a special kind of segue is run called an embed segue. You can see it in the storyboard - it’s the line that connects the child to the parent:
Add an identifier to that segue in the storyboard:
And a constant for it in the parent view controller:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
d) Then in the parent view controller, override the prepareForSegue()
method and check if segue.identifier
matches what you had set as the identifier. If it does, then you can get a reference to the child view controller through segue.destinationViewController
. Cast this as your child view controller, then you can set the parent to be its delegate:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == Constants.embedSegue {
let childViewController = segue.destinationViewController as ChildViewController
childViewController.delegate = self
}
}
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
e) Win!
2) Use NSNotification and NSNotificationCenter
You can think of these as similar to ActionScript events, however they don’t automatically bubble up through the view hierarchy like AS. Instead notifications are dispatched globally through NSNotificationCenter
. I prefer to only use this when there are multiple objects that need to listen for one particular event.
You can find more information about NSNotification
and NSNotificationCenter
here: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/