John Doe
John Doe

Reputation: 821

How to use delegates properly in Swift?

I read a lot about the delegates but in practice I cannot use it properly.

Description: I have A: UIViewController, B: UIView, C: UIViewController. I want to run segue from A: UIViewController to the C: UIViewController from the inside of B: UIView.

I've tried:

protocol SegueDelegate {
    func runSegue(identifier: String)
}

class B: UIView { ... }

where in my A: UIViewController:

override func viewDidLoad() {
    B().delegate = self
}

func runSegue(identifier: String) {
    self.performSegueWithIdentifier(identifier, sender: self)
}

and trying to call it via:

@IBAction func send(sender: AnyObject) {
    let a: SegueDelegate? = nil
    a!.runSegue("goToMainPage")
}

but I'm sure that I do not use it properly. Can anyone help me with it? I do not want just an answer. Please describe me it concept shortly

Upvotes: 1

Views: 718

Answers (2)

Kristof Van Landschoot
Kristof Van Landschoot

Reputation: 1455

Delegates are just a Design Pattern that you can use in a number of ways. You can look at the Apple Frameworks to see how and where to use delegates as examples. A table view delegate is probably the best known delegate in UIKit.

Delegates serve as a callback mechanism for code to communicate with an instance of an unknown class without knowing more than that that instance will respond to the methods of the delegate protocol.

An alternative to a delegate is to use a closure (what we used to call a block in Objective-C). When to use one vs. the other is a matter of taste. There are a couple of rules of thumb, like for instance outlined here.

What you are doing is, IMO, the proper way to use delegates. You separate the view functionality from the View Controller's functionalities via a delegate, and so the contract for your view is clear: the user needs to respond to the delegate method.

Your code works and is correct. I made a quick implementation here: https://github.com/kristofvanlandschoot/DelegateUsage/tree/master

The main difference from your example, and maybe that's the place where you made a mistake is the third part of your code where you should write something like:

@IBAction func send(sender: AnyObject) {
    delegate?.runSegue("segueAB")
}

Upvotes: 1

NiñoScript
NiñoScript

Reputation: 4593

There are multiple errors in your code, for example:

Here you are creating a new B, and setting A as a delegate of that new instance, no the one you actually want

override func viewDidLoad() {
    «B()».delegate = self
}

And here you are creating force unwrapping a nil value

@IBAction func send(sender: AnyObject) {
    let a: SegueDelegate? = «nil»
    «a!».runSegue("goToMainPage")
}

If what you want to do is tell A to perform a segue to C, from inside B, all you need to do is to call performSegueWithIdentifier on A

For example:

class B: UIView {
    weak var referenceToA: UIViewController? = nil // set this somewhere
    @IBAction func send(sender: AnyObject) {
        guard let a = referenceToA else {
            fatalError("you didn't set the reference to a view controller of class A")
        }
        a.performSegueWithIdentifier("goToMainPage", sender: self)
    }
}

Upvotes: 0

Related Questions