0

我有ThingThingManager

如果暂时没有人提到某个特定Thing的东西,我想ThingManager忘记它。

let manager = ThingManager()
let thing1 = Thing(name: "thing1")
manager.addThing(thing1)
manager.sawSomeThing(named: thing1.name)
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)
})

我已经尝试过基于块的计时器和基于 RunLoop 的计时器。他们似乎从来没有“走开”

struct Thing {
    var name: String
}

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

    func addThing(_ thing: Thing) {
        self.things[thing.name] = 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] {
                timer.invalidate()
            }
            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)
    }
}

更新,基于块的版本:https ://gist.github.com/lacyrhoades/f917b971e97fdecf9607669501ef6512

4

2 回答 2

1

而不是每个Thing我都会为每个计时器分配一个陈旧间隔ThingThingManager有一个计时器:

struct Thing {
    var name: String
}

extension Thing: Equatable {
    static func ==(lhs: Thing, rhs: Thing) -> Bool {
        return lhs.name == rhs.name
    }
}

extension Thing: Hashable {
    var hashValue: Int {
        return name.hashValue
    }
}

class ThingManager {
    let stalenessInterval: TimeInterval = -5
    var things = [String: Thing]()
    var staleness = [Thing: Date]()
    fileprivate var pruningTimer: DispatchSourceTimer!

    init() {
        pruningTimer = DispatchSource.makeTimerSource(queue: .main)
        pruningTimer.scheduleRepeating(deadline: DispatchTime.now(), interval: DispatchTimeInterval.milliseconds(500))
        pruningTimer.setEventHandler() {
            for (name, thing) in self.things {
                if let date = self.staleness[thing], date.timeIntervalSinceNow < self.stalenessInterval {
                    self.removeThing(named: name)
                }
            }
        }
        pruningTimer.resume()
    }

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

    func sawSomeThing(named name: String) {
        if let thing = things[name] {
            staleness[thing] = Date()
        }
    }

    func removeThing(named name: String) {
        if let removedThing = things.removeValue(forKey: name) {
            staleness.removeValue(forKey: removedThing)
        }
    }
}
于 2016-11-10T00:08:03.570 回答
1

我相信您只需要将计时器添加到当前的 runloop,而不是创建一个新的 Runloop 实例。

改变:

fileprivate var thingWatchingRunLoop = RunLoop()

至:

fileprivate var thingWatchingRunLoop = RunLoop.current

一切都应该正常工作!

于 2016-11-09T23:17:52.987 回答