Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass callback functions in Swift

Tags:

I have a simple class which init method takes an Int and a callback function.

class Timer {   var timer = NSTimer()   var handler: (Int) -> Void    init(duration: Int, handler: (Int) -> Void) {       self.duration = duration       self.handler = handler       self.start()   }   @objc func someMethod() {               self.handler(10)   } } 

Then in the ViewController I have this:

var timer = Timer(duration: 5, handler: displayTimeRemaining) func displayTimeRemaining(counter: Int) -> Void {     println(counter) } 

This doesn't work, I get the following:

'Int' is not a subtype of 'SecondViewController'

Edit 1: Adding full code.

Timer.swift

import UIKit  class Timer {     lazy var timer = NSTimer()     var handler: (Int) -> Void      let duration: Int     var elapsedTime: Int = 0      init(duration: Int, handler: (Int) -> Void) {         self.duration = duration         self.handler = handler         self.start()     }      func start() {         self.timer = NSTimer.scheduledTimerWithTimeInterval(1.0,             target: self,             selector: Selector("tick"),             userInfo: nil,             repeats: true)     }      func stop() {         timer.invalidate()     }      func tick() {         self.elapsedTime++          self.handler(10)          if self.elapsedTime == self.duration {             self.stop()         }     }      deinit {         self.timer.invalidate()     } } 

SecondViewController.swift

import UIKit  class SecondViewController: UIViewController {      @IBOutlet var cycleCounter: UILabel!     var number = 0      var timer = Timer(duration: 5, handler: displayTimeRemaining)      override func viewDidLoad() {         super.viewDidLoad()         // Do any additional setup after loading the view, typically from a nib.     }      override func didReceiveMemoryWarning() {         super.didReceiveMemoryWarning()         // Dispose of any resources that can be recreated.     }      @IBAction func btnIncrementCycle_Click(sender: UIButton){         cycleCounter.text = String(++number)         println(number)     }      func displayTimeRemaining(counter: Int) -> Void {         println(counter)     } } 

I just started with Swift so I'm very green. How are you supposed to pass callbacks? I've looked at examples and this should be working I think. Is my class defined incorrectly for the way I'm passing the callback?

Thanks

like image 823
Fernando Avatar asked Sep 07 '14 23:09

Fernando


People also ask

Can we pass function as a parameter in Swift?

Every function in Swift has a type, consisting of the function's parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions.

What are callback functions with an example?

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action. The above example is a synchronous callback, as it is executed immediately.

What are callbacks and delegates?

generically, a delegate is an object used to access a method external to the object owning the method, while a callback is a variable that holds a delegate. in C#, the terms are used interchangeably.


1 Answers

Ok, now with the full code I was able to replicate your issue. I'm not 100% sure what the cause is but I believe it has something to do with referencing a class method (displayTimeRemaining) before the class was instantiated. Here are a couple of ways around this:

Option 1: Declare the handler method outside of the SecondViewController class:

func displayTimeRemaining(counter: Int) -> Void {   println(counter) }   class SecondViewController: UIViewController {        // ...   var timer = Timer(duration: 5, handler: displayTimeRemaining) 

Option 2: Make displayTimeRemaining into a type method by adding the class keyword to function declaration.

class SecondViewController: UIViewController {    var timer: Timer = Timer(duration: 5, handler: SecondViewController.displayTimeRemaining)    class func displayTimeRemaining(counter: Int) -> Void {     println(counter)   } 

Option 3: I believe this will be the most inline with Swift's way of thinking - use a closure:

class SecondViewController: UIViewController {  var timer: Timer = Timer(duration: 5) {         println($0) //using Swift's anonymous method params     } 
like image 80
Eran Globen Avatar answered Sep 19 '22 09:09

Eran Globen