Ios 如何观察UserDefaults中的更改?
我的视图中有一个Ios 如何观察UserDefaults中的更改?,ios,swift,swiftui,Ios,Swift,Swiftui,我的视图中有一个@ObservedObject: struct HomeView: View { @ObservedObject var station = Station() var body: some View { Text(self.station.status) } 它根据站点中的字符串更新文本。状态: class Station: ObservableObject { @Published var status: String
@ObservedObject
:
struct HomeView: View {
@ObservedObject var station = Station()
var body: some View {
Text(self.station.status)
}
它根据站点中的字符串更新文本。状态
:
class Station: ObservableObject {
@Published var status: String = UserDefaults.standard.string(forKey: "status") ?? "OFFLINE" {
didSet {
UserDefaults.standard.set(status, forKey: "status")
}
}
但是,我需要更改我的AppDelegate
中的status
的值,因为这是我接收以下信息的地方:
但是,如果我在AppDelegate
中更改状态
UserDefaults
值,它将不会在我的视图中更新
当状态更改时,如何通知我视图中的@ObservedObject
编辑:忘记提到在上述示例中使用了SwiftUI的2.0测试版。我建议您使用环境对象,或者在需要时使用两者的组合。环境对象基本上是一个全局状态对象。因此,如果更改环境对象的“已发布”属性,它将反映您的视图。要设置它,您需要通过SceneDelegate将对象传递到初始视图,并且您可以使用整个视图层次结构中的状态。这也是跨非常远的同级视图传递数据的方法(或者如果您有更复杂的场景)
简单例子
在您的SceneDelegate.swift中:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView().environmentObject(GlobalState())
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
全局状态应符合可观察对象的要求。您应该将全局变量作为@Published放入其中
class GlobalState: ObservableObject {
@Published var isLoggedIn: Bool
init(isLoggedIn : Bool) {
self.isLoggedIn = isLoggedIn
}
}
发布变量的示例,与ScenedLegate中已显示的示例无关
这就是如何在视图中处理全局状态。您需要向它注入@EnvironmentObject包装器,如下所示:
struct ContentView: View {
@EnvironmentObject var globalState: GlobalState
var body: some View {
Text("Hello World")
}
}
现在,在您的例子中,您还需要处理AppDelegate中的状态。为了做到这一点,我建议您保护AppDelegate中的全局状态变量,并在传递到初始视图之前从ScenedLegate中的全局状态变量进行访问。要实现这一点,应在AppDelegate中添加以下内容:
var globalState : GlobalState!
static func shared() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
现在,您可以返回到SceneDelegate并执行以下操作,而不是直接初始化GlobalState:
let contentView = ContentView().environmentObject(AppDelegate.shared().globalState)
我建议您使用环境对象,或者在需要时使用两者的组合。环境对象基本上是一个全局状态对象。因此,如果更改环境对象的“已发布”属性,它将反映您的视图。要设置它,您需要通过SceneDelegate将对象传递到初始视图,并且您可以使用整个视图层次结构中的状态。这也是跨非常远的同级视图传递数据的方法(或者如果您有更复杂的场景)
简单例子
在您的SceneDelegate.swift中:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView().environmentObject(GlobalState())
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
全局状态应符合可观察对象的要求。您应该将全局变量作为@Published放入其中
class GlobalState: ObservableObject {
@Published var isLoggedIn: Bool
init(isLoggedIn : Bool) {
self.isLoggedIn = isLoggedIn
}
}
发布变量的示例,与ScenedLegate中已显示的示例无关
这就是如何在视图中处理全局状态。您需要向它注入@EnvironmentObject包装器,如下所示:
struct ContentView: View {
@EnvironmentObject var globalState: GlobalState
var body: some View {
Text("Hello World")
}
}
现在,在您的例子中,您还需要处理AppDelegate中的状态。为了做到这一点,我建议您保护AppDelegate中的全局状态变量,并在传递到初始视图之前从ScenedLegate中的全局状态变量进行访问。要实现这一点,应在AppDelegate中添加以下内容:
var globalState : GlobalState!
static func shared() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
现在,您可以返回到SceneDelegate并执行以下操作,而不是直接初始化GlobalState:
let contentView = ContentView().environmentObject(AppDelegate.shared().globalState)
这里有可能的解决办法
import Combine
// define key for observing
extension UserDefaults {
@objc dynamic var status: String {
get { string(forKey: "status") ?? "OFFLINE" }
set { setValue(newValue, forKey: "status") }
}
}
class Station: ObservableObject {
@Published var status: String = UserDefaults.standard.status {
didSet {
UserDefaults.standard.status = status
}
}
private var cancelable: AnyCancellable?
init() {
cancelable = UserDefaults.standard.publisher(for: \.status)
.sink(receiveValue: { [weak self] newValue in
guard let self = self else { return }
if newValue != self.status { // avoid cycling !!
self.status = newValue
}
})
}
}
注意:SwiftUI 2.0允许您通过AppStorage
直接在视图中使用/观察UserDefaults
,因此如果您仅在视图中需要该状态,您可以使用
struct SomeView: View {
@AppStorage("status") var status: String = "OFFLINE"
...
这里有可能的解决办法
import Combine
// define key for observing
extension UserDefaults {
@objc dynamic var status: String {
get { string(forKey: "status") ?? "OFFLINE" }
set { setValue(newValue, forKey: "status") }
}
}
class Station: ObservableObject {
@Published var status: String = UserDefaults.standard.status {
didSet {
UserDefaults.standard.status = status
}
}
private var cancelable: AnyCancellable?
init() {
cancelable = UserDefaults.standard.publisher(for: \.status)
.sink(receiveValue: { [weak self] newValue in
guard let self = self else { return }
if newValue != self.status { // avoid cycling !!
self.status = newValue
}
})
}
}
注意:SwiftUI 2.0允许您通过AppStorage
直接在视图中使用/观察UserDefaults
,因此如果您仅在视图中需要该状态,您可以使用
struct SomeView: View {
@AppStorage("status") var status: String = "OFFLINE"
...
@AppStorage
看起来正是我需要的-我会试试看。希望在我更改我的AppDelegate
中的状态
UserDefault
值时视图会更新。谢谢@AppStorage
看起来正是我需要的-我会试试看。希望在我更改我的AppDelegate
中的状态
UserDefault
值时视图会更新。谢谢你!谢谢你。然而,我认为Swiftui2.0中的@AppStorage
可能更有效,所以我将尝试一下:谢谢。但是,我认为SwiftUI 2.0中的@AppStorage
可能更有效,因此我将尝试以下方法: