snakeoil snakeoil - 10 months ago 53
Swift Question

Swift 3, make timer, add to dictionary, never goes off

I have


If no one mentions a specific
for a while, I want
to forget about it.

let manager = ThingManager()
let thing1 = Thing(name: "thing1")
print("Manager has this many things: ", manager.things.count)
Timer.scheduledTimer(withTimeInterval: 10.0, repeats: false, block: { (timer) in
// By now, the manager should have forgotten about the thing
print("Manager has this many things: ", manager.things.count)

I have tried both block-based timers and RunLoop-based timers. They don't ever seem to "go off"

struct Thing {
var name: String

class ThingManager {
var things: [String: Thing] = [:]
fileprivate var thingWatchingRunLoop = RunLoop()
fileprivate var thingWatchingQueue = .utility)
fileprivate var thingWatchingTimers: [String: Timer] = [:]

func addThing(_ thing: Thing) {
self.things[] = thing

func sawSomeThing(named name: String) {
self.thingWatchingQueue.async {
// re-up the timer so we don't forget about that thing
if let timer = self.thingWatchingTimers[name] {
let timer = Timer(timeInterval: 5.0, target: self, selector: #selector(self.timerWentOff(_:)), userInfo: ["name":name], repeats: false)
self.thingWatchingRunLoop.add(timer, forMode: .commonModes)
self.thingWatchingTimers[name] = timer

@objc func timerWentOff(_ timer: Timer) {
let info = timer.userInfo as! [String: String]
let name = info["name"]
self.removeThing(named: name!)

func removeThing(named name: String) {
self.things.removeValue(forKey: name)

Update, block-based version:

Answer Source

I believe you just need to add the timer to the current runloop instead of creating a new Runloop instance.


fileprivate var thingWatchingRunLoop = RunLoop()


fileprivate var thingWatchingRunLoop = RunLoop.current

and everything should be working properly!