我有Thing
和ThingManager
如果有一段时间没有人提到具体的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
答案 0 :(得分:1)
我相信你只需要将定时器添加到当前的runloop而不是创建一个新的Runloop实例。
变化:
fileprivate var thingWatchingRunLoop = RunLoop()
为:
fileprivate var thingWatchingRunLoop = RunLoop.current
一切都应该正常运作!
答案 1 :(得分:1)
相反,每个Thing
一个计时器我会为Thing
中的每个ThingManager
分配一个陈旧时间间隔,并且只有一个计时器:
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)
}
}
}