I am attempting to extend Foundation's Timer
class in Swift 3, adding a convenience initializer. But its call to the Foundation-provided initializer never returns.
The problem is illustrated in the following trivialized demo, which can be run as a Playground.
import Foundation
extension Timer {
convenience init(target: Any) {
print("Next statement never returns")
self.init(timeInterval: 1.0,
target: target,
selector: #selector(Target.fire),
userInfo: nil,
repeats: true)
print("This never executes")
}
}
class Target {
@objc func fire(_ timer: Timer) {
}
}
let target = Target()
let timer = Timer(target: target)
Console output:
Next statement never returns
To study further,
• I wrote similar code extending URLProtocol
(one of the only other Foundation classes with an instance initializer). Result: No problem.
• To eliminate the Objective-C stuff as a possible cause, I changed the wrapped initializer to init(timeInterval:repeats:block:)
method and provided a Swift closure. Result: Same problem.
I don't actually know the answer, but I see from running this in an actual app with a debugger that there's an infinite recursion (hence the hang). I suspect that this is because you're not in fact calling a designated initializer of Timer. This fact is not obvious, but if you try to subclass Timer and call
super.init(timeInterval...)
the compiler complains, and also there is an odd "not inherited" marking onsuper.init(timeInterval...)
in the header.I was able to work around the issue by calling
self.init(fireAt:...)
instead:Make of that what you will...