I'm trying to make an application in Swift on my Ubuntu (Ubuntu 15.10 wily, Swift swift-3.0.1-RELEASE) using the Perfect
library.
I would like to have a function called every X second. For that, I'm using the Timer
class of the Foundation
module:
class MyTimer {
init() {
var timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(MyTimer.onTimer(timer:)), userInfo: nil, repeats: true)
}
@objc func onTimer(timer: Timer) {
print("MyTimer.onTimer")
}
}
Despite finding several solutions with this code, the compilation failed:
$> swift build
Compile Swift Module 'my-app' (7 sources)
/home/.../Sources/MyTimer.swift:8:16: error: method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C
@objc func onTimer(timer: Timer) {
Another compilation error if I'm extending my class from NSObject
or if I removed the argument timer
:
$> swift build
Compile Swift Module 'my-app' (7 sources)
/home/.../Sources/MyTimer.swift:6:83: error: '#selector' can only be used with the Objective-C runtime
var timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(MyTimer.onTimer), userInfo: nil, repeats: true)
I tried to use the other declaration which do not use selectors:
class MyTimer {
init() {
print("MyTimer.init")
var timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {
timer in
print("MyTimer.onTimer")
}
}
}
The compilation works, but my second print is never called. I also tried to manually add my timer to the current RunLoop
:
class MyTimer {
init() {
print("MyTimer.init")
var timer = Timer(timeInterval: 1, repeats: true) {
timer in
print("MyTimer.onTimer")
}
RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
// timer.fire()
}
}
Never called again (and timer.fire()
only call one time my function). And finally:
class MyTimer {
init() {
print("MyTimer.init")
let timer = Timer(timeInterval: 1, repeats: true) {
timer in
print("MyTimer.onTimer")
}
RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
RunLoop.current.run(until: Date(timeIntervalSinceNow: 4.0))
}
}
My message "MyTimer.onTimer"
is printed 5 times, but my server (using the Perfect library) is started only at the end:
$> swift build && ./.build/debug/my-app 8400
Compile Swift Module 'my-app' (7 sources)
Linking ./.build/debug/my-app
MyTimer.init
MyTimer.onTimer
MyTimer.onTimer
MyTimer.onTimer
MyTimer.onTimer
MyTimer.onTimer
[INFO] Starting HTTP server on 0.0.0.0:8181
I do not know anymore what to try. It can be a problem with the Perfect library, but I can not find anything to solve my worries. I can maybe run a new thread, and start my timer in it, but it gets a bit complex?
If you are using Perfect seriously, please don’t use Foundation stuff. Try Perfect Threading: http://www.perfect.org/docs/thread.html
import PerfectThread
#if os(Linux)
import GlibC
#else
import Darwin
#endif
Threading.dispatch {
sleep(10) // wait for 10 seconds
doSomething()
}//end threading
it is safe and simple
very typical server side coding