【问题标题】:SwiftUI macOs AppDelegate detect the change of ObservedObjectSwiftUI macOs AppDelegate 检测 ObservedObject 的变化
【发布时间】:2021-10-15 00:53:05
【问题描述】:

我有下面的AppDelegate类,我想确定userPreferences.backgroundIsTransparent什么时候改变状态,必须调用AppDelegate里面的一个函数。

我看了一下这里:https://stackoverflow.com/a/58431723/8024296

但我不知道如何在我的情况下使用它。

我该怎么办?

AppDelegate:

import Cocoa
import SwiftUI

@main
class AppDelegate: NSObject, NSApplicationDelegate {
    var popover = NSPopover.init()
    var statusBar: StatusBarController?
    @Environment(\.colorScheme) var colorScheme
    
    @ObservedObject var userPreferences = UserPreferences.instance
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let contentView = ContentView()
        popover.contentSize = NSSize(width: 560, height: 360)
        popover.contentViewController = NSHostingController(rootView: contentView)
        statusBar = StatusBarController.init(popover)
        DistributedNotificationCenter.default.addObserver(self, selector: #selector(interfaceModeChanged(sender:)), name: NSNotification.Name(rawValue: "AppleInterfaceThemeChangedNotification"), object: nil)
    }
    
    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }
    
    @objc func interfaceModeChanged(sender: NSNotification) {
        //popover.backgroundColor = colorScheme == .dark ? #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1) : #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
        popover.backgroundColor = NSColor(named: "backgroundTheme")?.withAlphaComponent(userPreferences.backgroundIsTransparent ? 0.3 : 1.0)
        print("change", colorScheme)
    }
}
import EventKit
import ServiceManagement

private struct PreferencesKeys {
    static let backgroundIsTransparent = "backgroundIsTransparent"
    static let isDarkMode = "isDarkMode"
}

class UserPreferences: ObservableObject {
    static let instance = UserPreferences()
    
    private init() {
        // This prevents others from using the default '()' initializer for this class.
    }
    
    private static let defaults = UserDefaults.standard
    
    @Published var backgroundIsTransparent: Bool = {
        guard UserDefaults.standard.object(forKey: PreferencesKeys.backgroundIsTransparent) != nil else {
            return true
        }
        return UserDefaults.standard.bool(forKey: PreferencesKeys.backgroundIsTransparent)
    }() {
        didSet {
            UserPreferences.defaults.set(backgroundIsTransparent, forKey: PreferencesKeys.backgroundIsTransparent)
        }
    }
    
    @Published var isDarkMode: Bool = {
        guard UserDefaults.standard.object(forKey: PreferencesKeys.isDarkMode) != nil else {
            return true
        }
        return UserDefaults.standard.bool(forKey: PreferencesKeys.isDarkMode)
    }() {
        didSet {
            UserPreferences.defaults.set(isDarkMode, forKey: PreferencesKeys.isDarkMode)
        }
    }
    
}

【问题讨论】:

  • 我该怎么做不是一个被接受的问题。请不要问“为我做这个”。我投票结束这个问题,因为您附上了与您的问题无关的源代码。

标签: swift macos swiftui appkit observableobject


【解决方案1】:

有一种更复杂的方法可以观察UserDefaults

Combine框架为UserDefaults提供了一个发布者,其实就是一个Key-Value Observing Publisher

首先使您的backgroundIsTransparent 属性成为UserDefaults 的扩展

extension UserDefaults {
    @objc var backgroundIsTransparent: Bool {
        get {
            guard object(forKey: PreferencesKeys.backgroundIsTransparent) != nil else { return true }
            return bool(forKey: PreferencesKeys.backgroundIsTransparent)
        }
        set {
            set(newValue, forKey: PreferencesKeys.backgroundIsTransparent)
        }
    }
}

在 AppDelegate 中导入 Combine 并为订阅创建一个 Set

import Combine

@main
class AppDelegate: NSObject, NSApplicationDelegate { ...

    private var subscriptions = Set<AnyCancellable>()

applicationDidFinishLaunching 中添加发布者

    func applicationDidFinishLaunching(_ aNotification: Notification) {

    // .....

        UserDefaults.standard.publisher(for: \.backgroundIsTransparent)
            .sink { state in
                print(state)
                // do something with state
            }
            .store(in: &subscriptions)
    }

使用您的方法的另一种方法是将userPreferences 设为@StateObject

@StateObject var userPreferences = UserPreferences.instance

并观察backgroundIsTransparent

userPreferences.$backgroundIsTransparent
.sink { state in
   print(state)
   // do something with state
}
.store(in: &subscriptions)

【讨论】:

  • 完美的谢谢,它似乎工作。您会推荐使用这两种方法中的哪一种?
  • 绝对是第一。
  • 谢谢,如果你有时间我可以问你是否可以看看这个问题:stackoverflow.com/questions/68741461/…
猜你喜欢
  • 1970-01-01
  • 2017-03-16
  • 1970-01-01
  • 2022-06-18
  • 2020-02-08
  • 1970-01-01
  • 2020-08-01
  • 2020-01-12
  • 1970-01-01
相关资源
最近更新 更多