Question or problem with Swift language programming:
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
How to solve the problem:
Solution 1:
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 }
Solution 2:
Simplest way
override func viewDidLoad() { super.viewDidLoad() testFunc(index: 2, callback: { str in print(str) }) } func testFunc(index index: Int, callback: (String) -> Void) { callback("The number is \(index)") }
Solution 3:
Your problem is in the line:
var timer = NSTimer()
You cannot instantiate an NSTimer in this way. It has class methods that generate an object for you. The easiest way to get around the problem in this case is to make the definition lazy, like so:
lazy var timer = NSTimer()
In this way the value for timer won’t actually be touched until the start method which sets it up properly. NOTE: There is probably a safer way to do this.