Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do View Controller callback in Swift

Tags:

swift

cocoa

I am trying to do a callback from a child view controller back to its parent. The value passed back is printed successfully but I then get an EXC_BAD_INSTRUCTION.

In the parent view controller I construct the child controller like so:

let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let vc = storyboard.instantiateViewControllerWithIdentifier("dataEntryView") as? DataEntryViewController {
    dataEntryVC = vc
    vc.callback = calculateHeartRate
    self.presentViewController(dataEntryVC!, animated: true, completion: nil)
}

I call back from the child controller like this:

@IBAction func done(sender : AnyObject) {
    dismissModalViewControllerAnimated(true)
    if let cb = callback {
        cb(beatCount)
    }
}

To this function in the parent controller:

func calculateHeartRate(beats : Int?) {
    println("Beats = \(beats)")

    if beats {
        let heartrate = 60/secondsCount * beats!

        println("Heart rate \(heartrate)")
    }
}

The println correctly outputs to the console and then I get an exception on the "if beats {" line.

Is there something inherently wrong with doing a callback like this?

like image 246
zorro2b Avatar asked Jun 03 '26 18:06

zorro2b


2 Answers

I finally figured this out. It had nothing to do with the Optionals syntax I was using or with using a closure vs a function.

The root cause is that @IBOutlets are weak references.

When I changed my "done" method to immediate cache the value entered in a variable everything started working :)


Initialize

class DataEntryViewController: UIViewController {
    @IBOutlet var beatsText : UITextField
    var callback : ((Int?) -> Void)?

    var beatCount : Int?

    @IBAction func done(sender : AnyObject) {
        beatCount = beatsText.text.toInt()

        dismissModalViewControllerAnimated(true)
        if let cb = callback {
            cb(beatCount)
        }
    }

Usage

let dataEntryViewController = DataEntryViewController()
dataEntryViewController.callback = {
    (beatCount) in
    print(beatCount)
}
like image 98
zorro2b Avatar answered Jun 05 '26 07:06

zorro2b


You should unwrap the optional like

   if let beatCount = beats {
        let heartrate = 60/secondsCount * beatCount

        println("Heart rate \(heartrate)")
    }

But i would suggest you to use Closures instead of functions. Even though functions are special kind of closure, use of closure make sense just like completion blocks in ObjC

like image 44
Anil Varghese Avatar answered Jun 05 '26 08:06

Anil Varghese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!