Swift RunLoop:获取有关 currentMode 更改的通知

发布于 2025-01-10 20:04:57 字数 1258 浏览 3 评论 0原文

我有兴趣在 currentMode 属性时收到通知a href="https://developer.apple.com/documentation/foundation/runloop" rel="nofollow noreferrer">RunLoop 类更改,更具体地说,我有兴趣在以下情况下获取事件该模式正在进入 .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 的不同方法是什么变化?

I'm interested in getting notified when the currentMode property of the RunLoop class changes, more specifically, I'm interested in getting an event when the mode is entering .tracking state.

I've tried two different approaches:

This one simply doesn't work, what could be wrong with it?:

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)
        }
    }
}

This one works, but fires only once. I'd like to get the block executed each time the RunLoop enters the specific mode:

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")
        }
    }
}


What could be the solution to these two problems or a different approach to track RunLoop.currentMode changes?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

坏尐絯 2025-01-17 20:04:57

我完成了以下解决方案:

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
}

本质上,这个想法是为 defaulttracking 模式添加任务一旦运行循环进入其中任何一个,就相应地更新状态。

I finished with the following solution:

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()
            }
        }
    }
}

And then at call site I just use it like this:

@StateObject private var runLoopTracker = RunLoopModeTracker()
/// ...
.onChange(of: runLoopTracker.isTracking) { isTracking                 
/// isTracking value has changed to true
}

Essentially, the idea is to add the task for both the default and the tracking modes and once the runloop enters any of those, update the status correspondingly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文