iOS 小部件第一次在主屏幕中不读取 UserDefaults 值

iOS Widget does not read UserDeafults value for the first time in the home screen

我使用 UserDefaults 的值设置了 WidgetView。 为了在小部件和核心应用程序之间共享数据,我已经设置了appGroup。

let appGroupId = "group.com.myAppGroupId"
Text(UserDefaults(suiteName: appGroupId)!.object(forKey: "githubId") as? String ?? "??")

它在预览中显示很好,但是当我将它添加到主屏幕时,它无法读取属性。在相同的条件下,当我重建应用程序 (cmd+r) 时,主屏幕中的小部件可以很好地读取 UserDefaults 的值。

我猜不出原因。

++++++ 添加更多代码

实际上,我使用 属性 包装器将我的 githubId 定义为 UserDefaults。

extension UserDefaults {
    enum Key: String {
        case githubId
    }
  
    static let shared: UserDefaults = {
        let appGroupId = "group.com.myAppGroupId"
        return UserDefaults(suiteName: appGroupId)!
    }()

    @UserDefault(key: .githubId)
    static var githubId: String?
}

我的 属性 包装器看起来是这样的。

@propertyWrapper
struct UserDefault<Value> {
    let key: String
    let defaultValue: Value
    var container: UserDefaults = .shared
    private let publisher = PassthroughSubject<Value, Never>()
    
    var wrappedValue: Value {
        get {
            return container.object(forKey: key) as? Value ?? defaultValue
        }
        set {
            if let optional = newValue as? AnyOptional, optional.isNil {
                container.removeObject(forKey: key)
            } else {
                container.set(newValue, forKey: key) //this is where I set my value
            }
            publisher.send(newValue)
        }
    }

    var projectedValue: AnyPublisher<Value, Never> {
        return publisher.eraseToAnyPublisher()
    }
}

extension UserDefault where Value: ExpressibleByNilLiteral {
    init(key: UserDefaults.Key, _ container: UserDefaults = .shared) {
        self.init(key: key.rawValue, defaultValue: nil, container: container)
    }
}

LoginViewModel 中,我设置了 githubId 值。

class LoginViewModel: ObservableObject {
    @Published var githubId = UserDefaults.githubId ?? ""
    private var subscriptions = Set<AnyCancellable>()
    
    init() {
        $githubId
            .sink { githubId in
                UserDefaults.githubId = githubId
            }
            .store(in: &subscriptions)
    }
}

最后我在我的应用程序中使用了这个值,并且使用 UserDefaults.githubId

的小部件扩展

我上面写的代码(UserDefaults(suiteName: appGroupId)!.object(forKey: "githubId")UserDefaults.githubId的长版本。

是否可以选择使用@AppStorage? 您的代码可能如下所示:

@AppStorage('githubId) var id:String
Text(id)

.sink 在小部件中不起作用。

无论您想在小部件中显示什么,都必须在设置时间轴时完成。小部件未监听更改。

当有变化时,您必须从应用程序重新加载小部件时间线。将每个时间线条目视为屏幕截图。

WidgetCenter.shared.reloadAllTimelines()

重新加载是按计量进行的,因此请确保进行检查并且不要过度重新加载。