简体   繁体   中英

Swift: My Delegate Protocol Methods Need to Execute on Another View Controller

This is a really confusing problem so I will try to explain it as best as I can.

I have view controllers A, B, C, D and E

I'm not sure if I said that right, but to rephrase that, E needs to talk to A, but there's no segue between A and E to set the delegate.

A > B > C > D > E > A

I was told that when you use delegates in swift to access data between view controllers, you have to have a number of things in place:

  1. Define a delegate protocol for object B.
  2. Give object B an optional delegate variable. This variable should be weak.
  3. Make object B send messages to its delegate when something interesting happens, such as the user pressing the Cancel or Done buttons, or when it needs a piece of information.
  4. Make object A conform to the delegate protocol. It should put the name of the protocol in its class line and implement the methods from the protocol.
  5. Tell object B that object A is now its delegate.

I have been using prepapreforsegue to pass an object between view controllers as they navigate from one to the next, adding to it as they continue through the prepareforsegue method.

On the final view controller, I have protocol methods that are meant to be executed the first view controller, but because the last view controller segues from a different view controller. Problem is it's supposed to execute those methods on the first view controller. How can it reach it without that first view controller being able to tell the last view controller that it's the segue.

Here is some simple code to show you my problem and what I mean.

First:

import UIKit

class FirstViewController: UITableViewController, LastViewControllerDelegate {

var entry: EntryItem!

override func viewDidLoad() {
    super.viewDidLoad()
    entry = EntryItem()
    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

...

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

    //here's where I access the next view controller and set controller.entry and controller.delegate
    let controller = segue.destinationViewController as NextViewController
    controller.entry = entry
}

func lastViewControllerDidCancel(controller: LastViewController, didNotFinishAddingEntry draftentry: EntryItem){
    //this is where I wanna do something
    dismissViewControllerAnimated(true, completion: nil)
}
func lastViewController(controller: LastViewController, didFinishAddingEntry finalentry: EntryItem){
    //this is where I wanna do something
    dismissViewControllerAnimated(true, completion: nil)
}
}

Next 1:

import UIKit


class Next1ViewController: UITableViewController, LastViewControllerDelegate {

var entry: EntryItem!

override func viewDidLoad() {
    super.viewDidLoad()

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

...

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    //here's where I access the next view controller and set controller.entry and controller.delegate
    let controller = segue.destinationViewController as Next2ViewController
    controller.entry = entry
}


}

Next 2:

import UIKit


class Next2ViewController: UITableViewController, LastViewControllerDelegate {

    var entry: EntryItem!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    }

    ...

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        //here's where I access the next view controller and set controller.entry and controller.delegate
        let controller = segue.destinationViewController as LastViewController
        controller.entry = entry
        controller.delegate = ???? //Not self, but needs to be the first one.
    }


}

Last:

import UIKit

protocol LastViewControllerDelegate: class {
    func lastViewControllerDidCancel(controller: LastViewController, didNotFinishAddingEntry draftentry: EntryItem)
    func lastViewController(controller: LastViewController, didFinishAddingEntry finalentry: EntryItem)
}

class LastViewController: UITableViewController {

weak var delegate: LastViewControllerDelegate?
var entry: EntryItem!

override func viewDidLoad() {
    super.viewDidLoad()

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

...


@IBAction func cancel(){
    delegate?.lastViewControllerDidCancel(self, didNotFinishAddingEntry: entry)
}

@IBAction func done(){
    //do some final additions to entry object
    delegate?.lastViewController(self, didFinishAddingEntry: entry)
}

}

Can't you make your first view controller conform to all the delegate protocols (or, probably, make a single delegate protocol, otherwise you'd get casting problems) and then instead of doing this:

controller.delegate = self

Just do

controller.delegate = self.delegate

Alternatively, if you've got things several steps removed, using notifications is often better than delegation. If the intervening view controllers have no purpose for the delegate other than to forward it on, you should use notifications.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM