
[英]SwiftUI - Using 'ObservableObject' and @EnvironmentObject to Conditionally Display View
[英]Can't get SwiftUI View objects to update from @Published ObservableObject or @EnvironmentObject variables
我已经进行了大量搜索并阅读了一堆文章,但我无法让 SwiftUI 根据 model 中的变量变化动态更新视图,至少我正在做的事情是这样的。 基本上我想根据应用程序的UNNotificationSettings.UNAuthorizationStatus
更新视图。 我让应用程序在启动时检查状态并显示状态。 如果未确定状态,则点击文本将触发请求通知对话框。 但是,在用户允许或拒绝通知后,视图不会更新。 我确定我错过了一些基本的东西,因为我已经尝试了十几种方法,包括@Published ObservableObject
、 @ObservedObject
、 @EnvironmentObject
等。
struct ContentView: View {
@EnvironmentObject var theViewModel : TestViewModel
var body: some View {
VStack {
Text(verbatim: "Notifications are: \(theViewModel.notificationSettings.authorizationStatus)")
.padding()
}
.onTapGesture {
if theViewModel.notificationSettings.authorizationStatus == .notDetermined {
theViewModel.requestNotificationPermissions()
}
}
}
}
class TestViewModel : ObservableObject {
@Published var notificationSettings : UNNotificationSettings
init() {
notificationSettings = type(of:self).getNotificationSettings()!
}
func requestNotificationPermissions() {
let permissionsToRequest : UNAuthorizationOptions = [.alert, .sound, .carPlay, .announcement, .badge]
UNUserNotificationCenter.current().requestAuthorization(options: permissionsToRequest) { granted, error in
if granted {
print("notification request GRANTED")
}
else {
print("notification request DENIED")
}
if let error = error {
print("Error requesting notifications:\n\(error)")
}
else {
DispatchQueue.main.sync {
self.notificationSettings = type(of:self).getNotificationSettings()!
}
}
}
}
static func getNotificationSettings() -> UNNotificationSettings? {
var settings : UNNotificationSettings?
let start = Date()
let semaphore = DispatchSemaphore(value: 0)
UNUserNotificationCenter.current().getNotificationSettings { notificationSettings in
settings = notificationSettings
semaphore.signal()
}
semaphore.wait()
while settings == nil {
let elapsed = start.distance(to: Date())
Thread.sleep(forTimeInterval: TimeInterval(0.001))
if elapsed > TimeInterval(1) {
print("ERROR: did not get notification settings in less than a second, giving up!")
break
}
}
if settings != nil {
print("\(Date()) Notifications are: \(settings!.authorizationStatus)")
}
return settings
}
}
func getUNAuthorizationStatusString(_ authStatus : UNAuthorizationStatus) -> String {
switch authStatus {
case .notDetermined: return "not determined"
case .denied: return "denied"
case .authorized: return "authorized"
case .provisional: return "provisional"
case .ephemeral: return "ephemeral"
@unknown default: return "unknown case with rawValue \(authStatus.rawValue)"
}
}
extension UNAuthorizationStatus : CustomStringConvertible {
public var description: String {
return getUNAuthorizationStatusString(self)
}
}
extension String.StringInterpolation {
mutating func appendInterpolation(_ authStatus: UNAuthorizationStatus) {
appendLiteral(getUNAuthorizationStatusString(authStatus))
}
}
编辑:我尝试添加 objectWillChange 但视图仍未更新。
class TestViewModel : ObservableObject {
let objectWillChange = ObservableObjectPublisher()
@Published var notificationSettings : UNNotificationSettings {
willSet {
objectWillChange.send()
}
}
init() {
notificationSettings = type(of:self).getNotificationSettings()!
}
根据苹果文档,@Published 等属性包装器应该保存值。 UNNotificationSettings是一个引用类型。 由于 class 发生变异并且指针永远不会改变,@Publushed 不知道你改变了任何东西。 发布一个值(它创建一个结构并从他的类中初始化它)或手动手动发送objectwillChange消息。
虽然我无法使用objectWillChange
手动使用它,但我确实创建了一个基本的工作系统,如下所示。 上面的问题中没有重复某些功能。
struct TestModel {
var notificationAuthorizationStatus : UNAuthorizationStatus
init() {
notificationAuthorizationStatus = getNotificationSettings()!.authorizationStatus
}
}
class TestViewModel : ObservableObject {
@Published var theModel = TestModel()
func requestAndUpdateNotificationStatus() {
requestNotificationPermissions()
theModel.notificationAuthorizationStatus = getNotificationSettings()!.authorizationStatus
}
}
struct ContentView: View {
@ObservedObject var theViewModel : TestViewModel
var body: some View {
VStack {
Button("Tap to update") {
theViewModel.requestAndUpdateNotificationStatus()
}
.padding()
switch theViewModel.theModel.notificationAuthorizationStatus {
case .notDetermined: Text("Notifications have not been requested yet.")
case .denied: Text("Notifications are denied.")
case .authorized: Text("Notifications are authorized.")
case .provisional: Text("Notifications are provisional.")
case .ephemeral: Text("Notifications are ephemeral.")
@unknown default: Text("Notifications status is an unexpected state.")
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.