0

I've been looking into how delegation works. You define a protocol in controller A, create a delegate variable, and call the function through the delegate. Then, in controller B, you conform to the protocol, implement methods, and then use prepareForSegue to tell controller A that controller B is the delegate.

But this involves A -> B -> A. I need to know how to do A -> B. I've been trying to do this through the following code:

Declare the protocol in controller A

protocol CellDataDelegate {

    func userDidTapCell(data: String)
}

Create a delegate variable in A

var cellDelegate: CellDataDelegate? = nil

Call the function in the delegate in A when cell tapped

if cellDelegate != nil {

    let cellKey = keys[indexPath.row].cellKey
    cellDelegate?.userDidTapCell(data: cellKey)

    self.performSegue(withIdentifier: "showDetails", sender: self)
}

Add the delegate to controller B and conform to the method

class DetailsVC: UIViewController, CellDataDelegate

The function:

func userDidTapCell(data: String) {

    useData(cellKey: data)
}

The problem here is the last part of the delegation process. I can't use prepareForSegue to do the controllerA.delegate = self part because I don't want to go back to controller A, I need to stay in controller B. So how do I tell controller A that B is the delegate?

  • I don't get how delegation here relates to segue. The segue that is performed is the one that is set up in interface builder, what you do in prepare for segue does not affect which view controller you end up in? Am I misunderstanding what you are trying to do? – Ilya Lapan Oct 23 '16 at 16:33
  • Can you explain more clearly what you are trying to do? Which controller you want to be the delegate of what, and which segues are you trying to perform? – Ilya Lapan Oct 23 '16 at 16:35
  • @IlyaLapan When I tap on a cell, my goal is to get from one controller to another while passing data from that first controller to the second. Going to the controller is no issue, it's the passing data through the delegate part. According to questions like [this](http://stackoverflow.com/questions/31222275/swift-delegate-beetween-two-view-controller-without-segue), you have to create an instance of the view controller you're going to in the prepareForSegue function and tell it that the controller that is sending data is its delegate. Another example https://www.youtube.com/watch?v=KhqXUi1SF4s – Faisal Lalani Oct 23 '16 at 16:52
  • you can just drag out an IBOutlet from you cell into your view controller and then perform segue. In prepare for segue cast your destination view controller as B and pass the data. You need to add your function declarations to you question too, as otherwise it is hard to understand what is calling what and what is supposed to be where. Comment you code to show which class which snippet belongs to too. – Ilya Lapan Oct 23 '16 at 17:05

3 Answers3

1

Protocol Delegates are usually used to pass data to a previous UIViewController than the present one in the navigation stack(in case of popViewController) because the UIViewController to which the data is to be sent needs to be present in the memory. In your case you havn't initialised UIViewController B in memory for the method of protocol delegate to execute.

There are simple ways to send data to the next UIViewControllers in the navigation stack.

Your UIViewController B should have a receiving variable to store data sent from the UIViewController A

class DestinationVC : UIViewController
{
    receivingVariable = AnyObject? // can be of any data type depending on the data
}

Method 1: Using Storyboard ID

let destinationVC = self.storyboard.instantiateViewControllerWithIdentifier("DestinationVC") as DestinationVC 
destinationVC.receivingVariable = dataInFirstViewControllerToBePassed
self.navigationController.pushViewController(destinationVC , animated: true)

Method 2: Using prepareForSegue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
{
    let destinationVC = segue.destinationViewController as DestinationVC 
    destinationVC.receivingVariable = dataInFirstViewControllerToBePassed
}

Multiple segues from UIViewController A to any other UIViewController will cause in execution of prepareForSegue every single time and might crash the application as other classes of UIViewControllers would have no such parameters as receivingVariable which is present in UIViewController B. This can be easily countered; use of multiple segues can be done simply using if else or switch modules on segue.identifier which is a parameter of segue.

Note: UILabel, UIButton and another other UI element's attribute cannot be assigned in this manner because these element load in the memory in the func loadView() of UIViewController lifecycle as they are not set to initialise when you initialise the class of UIViewController B as mentioned above.

0

I don't think you need to use delegate pattern here. If you are trying to achieve this. You have some cells on view controller A and now you want to display details of cell(on click) in view controller B. You can declare cell key as the property in view controller B.

class B: UIViewController {
    let cellKey: String!
}

And set the above key in prepare for segue method

if (segue.identifier == "segueToViewControllerB") {
    let vc = segue.destinationViewController as B
    vc.cellKey= "1"
}
  • I've implemented this and chose to avoid it because of what I read [here](http://stackoverflow.com/questions/27457091/is-prepareforsegue-right-way-of-passing-value-between-view-controllers). But if there's no other way of doing it, I'll use this. – Faisal Lalani Oct 23 '16 at 16:56
0

I think you are misunderstanding the point of the question you referenced. The question above explained the what is happening in a lot of detail, but here is a short answer, for those who are lazy: do NOT you prepareForSegue to pass information bottom to top (i.e. from child view controller to parent), but most certainly DO use it to pass top to bottom.

Ilya Lapan
  • 1,103
  • 2
  • 12
  • 31