当RunLoop类的currentMode属性发生更改时,我有兴趣得到通知,更具体地说,当模式进入.tracking
状态时,我感兴趣得到事件。
我尝试了两种不同的方法:
这个根本不起作用,它可能有什么问题?:
import Foundation
public final class RunLoopTracker {
private let runLoop: RunLoop
private var observation: NSKeyValueObservation?
public init(runLoop: RunLoop) {
self.runLoop = runLoop
}
public func attach() {
observation = runLoop.observe(.currentMode) { runLoop, change in
print(change)
}
}
}
这个有效,但只发射一次。我想在每次RunLoop
进入特定模式时执行块:
import Foundation
public final class RunLoopTracker2 {
private let runLoop: RunLoop
private var observation: NSKeyValueObservation?
public init(runLoop: RunLoop) {
self.runLoop = runLoop
}
public func attach() {
runLoop.perform(inModes: [.tracking]) {
print("Entering the tracking mode, send notification")
}
}
}
这两个问题的解决方案是什么,或者用不同的方法来跟踪RunLoop.currentMode
的变化?
我完成了以下解决方案:
import Foundation
import Combine
final class RunLoopModeTracker: ObservableObject {
@Published var isTracking = false
private let runLoop: RunLoop
private var taskSet = false
public init(runLoop: RunLoop = .main) {
self.runLoop = runLoop
submitTaskForTrackingMode()
}
private func submitTaskForTrackingMode() {
if !taskSet {
runLoop.perform(inModes: [.tracking]) { [weak self] in
self?.notify()
}
taskSet = true
}
}
private func notify() {
isTracking = true
taskSet = false
submitTaskForDefaultMode()
}
private func submitTaskForDefaultMode() {
if !taskSet {
runLoop.perform(inModes: [.default]) { [weak self] in
guard let self = self else {return}
self.isTracking = false
self.submitTaskForTrackingMode()
}
}
}
}
然后在呼叫站点,我就这样使用它:
@StateObject private var runLoopTracker = RunLoopModeTracker()
/// ...
.onChange(of: runLoopTracker.isTracking) { isTracking
/// isTracking value has changed to true
}
本质上,这个想法是为default
和tracking
模式添加任务,一旦运行循环进入其中任何一个模式,就相应地更新状态。