4

Could you please help, how to use Timer instance in Swift 4 on Linux Ubuntu 16.04?

When I try to do:

let timer = Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(MyClass.myMethod), userInfo: nil, repeats: true)

I got error: error: '#selector' can only be used with the Objective-C runtime

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Serhii Didanov
  • 2,200
  • 1
  • 16
  • 31

2 Answers2

7

You can use the block-based timer functions on Linux. Here is a minimal self-contained example which compiles and runs both in Xcode 9.1 and on https://swift.sandbox.bluemix.net/#/repl:

import Foundation
import CoreFoundation

let timer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { timer in
    print("In timer function")
    exit(0)
}

CFRunLoopRun()

(I added the exit(0) only because the IBM Swift Sandbox limits the program execution time to 5 seconds.)

Alternatively, use a DispatchSourceTimer as demonstrated here.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Where to place CFRunLoopRun()? Because if I place it inside init() {}, Initialization of instance do not finished... – Serhii Didanov Nov 21 '17 at 08:21
  • @SergeyDi: At the end of main.swift. – Timers need a run loop, and that would start it. – Martin R Nov 21 '17 at 08:22
  • Instance with timer is very far from main.swift. Also, I am checking now DispatchSourceTimer... – Serhii Didanov Nov 21 '17 at 08:26
  • @SergeyDi: If you program uses timers then you need some event loop. Either a CFRunloop (for Timer), or a GCD event loop with `dispatchMain()` – Martin R Nov 21 '17 at 08:33
  • 1
    I seemed fail to compile this code: scheduledTimer(withTimeInterval:repeats:block:) is only available on OS X 10.12 or newer, any ideas? I'm using the vapor framework. – Jay Zhao May 23 '18 at 02:09
  • @JayZhao: This question was about Linux, not about OS X. – Martin R May 23 '18 at 05:33
  • @MartinR I'm using Linux, that's why I'm getting the compile error. – Jay Zhao May 23 '18 at 06:32
  • 1
    @JayZhao: Perhaps that is a problem of Vapor: The method is available on the (Linux) server, but not on the local Mac where the code is developed. – I have no experience with Vapor, so unfortunately I can not help. – Martin R May 23 '18 at 06:38
  • 1
    @JayZhao & Martin R, The DispatchQueue/DispatchSource method is perhaps a better solution if you are developing to run on Linux but developing under MacOS. The regular Timer requires you either target your project to MacOS 10.12 or higher, or using a conditional compile directive. Sergey Di's is one that works in both places. – drewster Aug 10 '18 at 16:34
4

Thanks to @Martin R, I got the final code for Swift 4 on Ubuntu 16.04:

import Foundation
import Dispatch

class MyClassWithTimer {

  var timer: DispatchSourceTimer?

  init() {
    startTimer()
  }

  func startTimer() {
    let queue = DispatchQueue(label: "com.domain.app.timer")
    timer = DispatchSource.makeTimerSource(queue: queue)
    timer?.schedule(deadline: .now(), repeating: 2.0, leeway: .seconds(0))
    timer?.setEventHandler { [weak self] in
        print("Execute timer action")
        self?.timerAction()
    }
    timer?.resume()
  }

  func timerAction() {
    print("Do something")
  }

  func stopTimer() {
      timer?.cancel()
      timer = nil
  }

  deinit {
      self.stopTimer()
  }
}
Serhii Didanov
  • 2,200
  • 1
  • 16
  • 31