Faisal Lalani
Faisal Lalani

Reputation: 67

Passing data with protocols without going back to original controller

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?

Upvotes: 0

Views: 150

Answers (3)

Ilya  Lapan
Ilya Lapan

Reputation: 1103

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.

Upvotes: 0

Vedant Mahant
Vedant Mahant

Reputation: 149

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.

Upvotes: 1

user4527951
user4527951

Reputation:

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"
}

Upvotes: 0

Related Questions