Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass a Swift function to NSTimer

Tags:

ios

swift

nstimer

I have some function inside another function. in function1 i want to use NSTimer to call func2 after some time like this:

func myFunc1()
{
   NSTimer.scheduledTimerWithTimeInterval(1, target: ??, selector:#selector(myFunc2()), userInfo: nil, repeats: false)
   func myFunc2()
   {
      // do something...
   }
}

What is the right "target" value that i should pass there? is it even possible?

like image 379
Asi Givati Avatar asked Dec 04 '22 00:12

Asi Givati


2 Answers

If you are targeting pre-iOS 10, you can't pass a function to NSTimer because no API was introduced at that time to support closure callbacks.

iOS 10 and later Approach

// swift 2.x users should still use NSTimer instead
Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { timer in
    // ...
}

Generic Approach

You can add this class, and reuse it anytime:

final class TimerInvocation: NSObject {

    var callback: () -> ()

    init(callback: @escaping () -> ()) {
        self.callback = callback
    }

    func invoke() {
        callback()
    }
}

extension Timer {

    static func scheduleTimer(timeInterval: TimeInterval, repeats: Bool, invocation: TimerInvocation) {

        Timer.scheduledTimer(
            timeInterval: timeInterval,
            target: invocation,
            selector: #selector(TimerInvocation.invoke(timer:)),
            userInfo: nil,
            repeats: repeats)
    }
}

With this class, you can simply do this now:

let invocation = TimerInvocation {
    /* invocation code here */
}

NSTimer.scheduledTimerWithTimeInterval(1, target: invocation, selector:#selector(TimerInvocation.invoke), userInfo: nil, repeats: false)

You don't have to worry about retaining the invocation variable since it is retained by NSTimer

like image 124
Mazyod Avatar answered Dec 12 '22 06:12

Mazyod


In Swift 3, the new Timer has a factory method that takes a closure:

Timer.scheduledTimer(withTimeInterval: TimeInterval, repeats: Bool, block: (Timer) -> Void)

In your case, you could call it like this using trailing closure syntax:

Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
    // do something
}

Note: This is only available in iOS 10 or newer.

like image 22
vacawama Avatar answered Dec 12 '22 06:12

vacawama