1

我已经进行了大量搜索并阅读了一堆文章,但我无法让 SwiftUI 根据模型中不断变化的变量动态更新视图,至少我正在做的事情是这样的。基本上我想根据应用程序的UNNotificationSettings.UNAuthorizationStatus. 我让应用程序在启动时检查状态并显示状态。如果未确定状态,则点击文本将触发请求通知对话框。但是,在用户允许或拒绝通知后,视图不会更新。我确定我错过了一些基本的东西,因为我已经尝试了十几种方法,包括 with @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()!
    }
4

2 回答 2

2

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

于 2021-01-16T02:46:34.710 回答
0

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

于 2021-01-23T16:17:23.207 回答