gpt4 book ai didi

ios - 如何在 SwiftUI 中引用外部 iOS 系统状态更新?

转载 作者:行者123 更新时间:2023-12-04 13:27:04 25 4
gpt4 key购买 nike

这个问题有很多可能的变体,但以 CNAuthorizationStatus 为例。返回者 CNContactStore.authorizationStatus(for: .contacts) ,可以是 notDetermined , restricted , denied , 或 authorized .我的目标是始终在我的应用程序的 UI 中显示当前的授权状态。
要将其暴露给 SwiftUI,我可能会创建一个 ObservableObjectModelDatacontacts属性(property):

final class ModelData: ObservableObject {
@Published var contacts = Contacts.shared
}
哪里 contacts包含我的联系人特定型号代码,包括授权:
class Contacts {
fileprivate let store = CNContactStore()
static let shared = Contacts()

enum Authorization {
case notDetermined
case restricted
case denied
case authorized
}

var authorization: Authorization {
switch CNContactStore.authorizationStatus(for: .contacts) {
case .notDetermined:
return .notDetermined
case .restricted:
return .restricted
case .denied:
return .denied
case .authorized:
return .authorized
@unknown default:
return .notDetermined
}
}
}
我可能会添加一个按钮可以调用以请求访问的方法:
    func requestAccess(handler: @escaping (Bool, Error?) -> Void) {
store.requestAccess(for: .contacts) { (granted, error) in
// TODO: tell SwiftUI views to re-check authorization

DispatchQueue.main.async {
handler(granted, error)
}
}
}
为了简单起见,说我的观点只是:
Text(String(describing: modelData.contacts.authorization))
所以我的问题是:
  • 鉴于 ModelData().contacts.authorization调用 getter 函数,而不是属性,当我知道它已更改时如何通知 SwiftUI View (例如 TODO 在 requestAccess() 函数中的位置)?
  • 鉴于用户可以在“设置”应用程序中切换权限(即,值可能会从我下面更改),我如何确保 View 状态始终更新? (我是否需要订阅 NSNotification 并类似地强制刷新?或者有更好的方法吗?)
  • 最佳答案

    正如@jnpdx 指出的那样 - 使用 @Published使用类(尤其是从不改变的单例)可能不会产生任何有用的结果 @Published表现得像 CurrentValueSubject并且只有在它在后台存储/观察的值发生变化时才会触发更新。因为它存储了对 Contacts.shared 的引用例如,它不会为授权状态更改提供/触发任何更新。
    现在回答你的问题——
    鉴于 ModelData().contacts.authorization调用 getter 函数,而不是属性,当我知道它已更改时如何通知 SwiftUI View
    只要您直接访问 getter 中的值 ModelData().contacts.authorization ,它只是 Contacts.Authorization 的值不提供任何可观察性的类型。
    因此,即使该值随时间发生变化(从 .notDetermined => .authorized ),也没有存储(引用点)可供我们比较它自上次以来是否发生变化。
    我们必须定义一个可以比较旧/新值并根据需要触发更新的存储。这可以通过标记 authorization 来实现。如 @Published喜欢以下 -

    import SwiftUI
    import Contacts

    final class Contacts: ObservableObject {
    fileprivate let store = CNContactStore()
    static let shared = Contacts()

    enum Authorization {
    case notDetermined
    case restricted
    case denied
    case authorized
    }

    /// Since we have a storage (and hence a way to compare old/new status values)
    /// Anytime a new ( != old ) value is assigned to this
    /// It triggers `.send()` which triggers an update
    @Published var authorization: Authorization = .notDetermined

    init() {
    self.refreshAuthorizationStatus()
    }

    private func refreshAuthorizationStatus() {
    authorization = self.currentAuthorization()
    }

    private func currentAuthorization() -> Authorization {
    switch CNContactStore.authorizationStatus(for: .contacts) {
    case .notDetermined:
    return .notDetermined
    case .restricted:
    return .restricted
    case .denied:
    return .denied
    case .authorized:
    return .authorized
    @unknown default:
    return .notDetermined
    }
    }

    func requestAccess() {
    store.requestAccess(for: .contacts) { [weak self] (granted, error) in
    DispatchQueue.main.async {
    self?.refreshAuthorizationStatus()
    }
    }
    }

    }

    struct ContentView: View {
    @ObservedObject var contacts = Contacts.shared

    var body: some View {
    VStack(spacing: 16) {
    Text(String(describing: contacts.authorization))

    if contacts.authorization == .notDetermined {
    Button("Request Access", action: {
    contacts.requestAccess()
    })
    }
    }
    }
    }

    关于ios - 如何在 SwiftUI 中引用外部 iOS 系统状态更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67796952/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com