【问题标题】:Can't get SwiftUI View objects to update from @Published ObservableObject or @EnvironmentObject variables无法从 @Published ObservableObject 或 @EnvironmentObject 变量获取要更新的 SwiftUI View 对象
【发布时间】:2021-04-21 01:26:46
【问题描述】:

我已经进行了大量搜索并阅读了一堆文章,但我无法让 SwiftUI 根据模型中不断变化的变量动态更新视图,至少我正在做的事情是这样的。基本上我想根据应用程序的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()!
    }

【问题讨论】:

    标签: swift swiftui nsnotificationcenter observableobject environmentobject


    【解决方案1】:

    虽然我无法使用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.")
                }
            }
        }
    }
    
    

    【讨论】:

      【解决方案2】:

      根据苹果文档,@Published 等属性包装器应该保存值。 UNNotificationSettings 是一个引用类型。由于类发生了变异并且指针永远不会改变,@Publushed 不知道你改变了任何东西。要么发布一个值(它创建一个结构并从他的类中初始化它),要么手动手动发送objectwillChange 消息。

      【讨论】:

      • 谢谢,这很有道理。我尝试添加 objectWillChange 但这似乎并没有解决它。我可能会尝试在生产中使用 struct 路线,但我很好奇为什么这没有解决它。
      猜你喜欢
      • 2021-10-14
      • 1970-01-01
      • 2021-09-07
      • 2020-01-07
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 2021-01-25
      • 2020-10-18
      相关资源
      最近更新 更多