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()
重新加载是按计量进行的,因此请确保进行检查并且不要过度重新加载。
我使用 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()
重新加载是按计量进行的,因此请确保进行检查并且不要过度重新加载。