Search code examples
iostimerschedule

Using schedule() on an iOS project


I'm trying to use schedule(deadline:repeating:leeway:) on an iOS project. In a counterpart macOS project it works fine, but in the iOS project I get an error:

'schedule(deadline:repeating:leeway:)' is unavailable

Here is a part of the code:

var timeoutTimer : DispatchSourceTimer?

func startUpdateTimer(){
        let delay : DispatchTime = .now() + .seconds(3)

        if timeoutTimer == nil {
            timeoutTimer = DispatchSource.makeTimerSource()
            timeoutTimer!.schedule(deadline: delay, repeating: 0) // Error: 'schedule(deadline:repeating:leeway:)' is unavailable
        ...

Doc 1: https://developer.apple.com/documentation/dispatch/dispatchsourcetimer/2920395-schedule

I would like to understand if I'm doing something wrong, could someone tell me if this code should work on iOS?

PS Using scheduleRepeating(deadline:interval:leeway:) which is deprecated instead of schedule(deadline:repeating:leeway:) seems to work. At the moment unfortunately I do not have enough knowledge to understand how the two statements differ.

timeoutTimer!.scheduleRepeating(deadline: delay, interval: 0)

Doc 2: https://developer.apple.com/documentation/dispatch/dispatchsourcetimer/2016072-schedulerepeating


Solution

  • scheduleRepeating(deadline:interval:leeway:) was introduced in iOS 7/macOS 10.9 and has been deprecated in iOS 11/macOS 10.13.

    Initially Apple offered scheduleRepeating and scheduleOneshot variants but this made no sense as if a timer is repeating or oneshot can be deducted solely by arguments passed to the function. Now they only offer schedule(deadline:repeating:leeway:), and if called with a non-zero value for repeating, the timer is repeating, otherwise it is oneshot.

    However, please note that in fact GCD timers are not real objects, neither Swift objects nor Objective-C objects, in fact they are C structures represented as opaque pointers. If you create such a GCD object in C or Obj-C, the code is like this:

    dispatch_source_t ds = dispatch_source_create(
        DISPATCH_SOURCE_TYPE_TIMER, 0, 0, someQueue
    );
    dispatch_source_set_timer(ds, startTime, interval, leeway);
    

    Making GCD Objects appear as Swift objects is actually some "magic" built into Xcode and the Swift SDK. schedule(deadline:repeating:leeway:) is only available if you use Xcode 9+ and Swift 4. If you use Xcode 8.x or if you use Swift 3 in Xcode 9+, then only the deprecated scheduleRepeating(deadline:interval:leeway:) is available.

    Unlike with other API, that's not a question of the iOS/macOS SDK version you build for, as this magic is not provided by the iOS/macOS SDK, it depends on the Swift SDK version you build for and this version is independent of the target operating system, as the SDK is embedded into your app and thus shipped together with your app.

    That's why you can use schedule(deadline:repeating:leeway:) in Swift 4 in Xcode 9+ and still deploy all the way down to iOS 7.0/macOS 10.9, since only for your Swift code the call has changed, internally it uses the same GCD API calls that the deprecated methods were using before, so the compiled code runs just fine even on these old OS versions.

    To answer your question on how the statements differ: Well, they have different names and the arguments have different names, other than that the argument types are identically and they also work identically.