gpt4 book ai didi

ios - 如何在 SwiftUI 中进行异步更新后解雇发布者?

转载 作者:行者123 更新时间:2023-12-01 21:25:40 25 4
gpt4 key购买 nike

问题
当我的存储类中的模型在主线程上异步更新时,SwiftUI View 不会自动呈现由 ViewModel 提供的模型切片。
假设解决方案
需要自定义发布者/ promise 将 View/ViewModel/Factory/Store 链接在一起,因为引用不会触发异步更新的更新。
堵塞
我该怎么写?我尝试向 Store 类添加一个 promise ,但 Xcode 警告调用 sink(receiveValue:) 的结果未使用。我显然不了解 promise /发布者,大多数教程都使用 URLSession 及其 dataTaskPublisher (不是我的情况)。
我尝试了示例 in this Apple Dev Forums thread关于工厂和商店类(class),但没有骰子。我显然不明白。 In this answer, @Asperi suggested the View listen to a publisher并更新 @State 变量,但由于我的模型是私有(private)的,因此我缺乏该方法的目标。
缩写代码

  • 工厂实例化具有依赖关系的 ContactStore 类;一个引用被传递给 ViewModels。
  • 虚拟机使用计算变量控制对私有(private)存储的访问。 View 调用 ViewModel 中修改状态的函数,如果同步的话效果很好。

  • Factory.swift

    import SwiftUI
    import Combine

    class MainFactory {

    init() {
    ...
    self.contactStore = ContactStore()
    }

    private var preferences: Preferences
    private var contactStore: ContactStore

    ...

    func makeOnboardingVM() -> OnboardingVM {
    OnboardingVM(preferences: preferences, contactStore: contactStore)
    }

    }

    ContactStore.swift
    final class ContactStore {

    private(set) var authorizationStatus: CNAuthorizationStatus = .notDetermined
    private(set) var contacts: [Contact] = [Contact]()
    private(set) var errors: [Error] = [Error]()

    private lazy var initialImporter = CNContactImporterForiOS14(converter: CNContactConverterForiOS14(),
    predictor: UnidentifiedSelfContactFavoritesPredictor())
    }

    // MARK: - IMPORT

    extension ContactStore {
    /// Full import during app onboarding. Work conducted on background thread.
    func requestAccessAndImportPhoneContacts(completion: @escaping (Bool) -> Void) {
    CNContactStore().requestAccess(for: .contacts) { [weak self] (didAllow, possibleError) in
    guard didAllow else {
    DispatchQueue.main.async { completion(didAllow) }
    return
    }
    DispatchQueue.main.async { completion(didAllow) }
    self?.importContacts()
    }
    }

    private func importContacts() {
    initialImporter.importAllContactsOnUserInitiatedThread { [weak self] importResult in
    DispatchQueue.main.async {
    switch importResult {
    case .success(let importedContacts):

    self?.contacts = importedContacts
    case .failure(let error):
    self?.errors.append(error)
    }
    }
    }
    }
    }
    OnboardingViewModel.swift
    import SwiftUI
    import Contacts

    class OnboardingVM: ObservableObject {

    init(preferences: Preferences, contactStore: ContactStore) {
    self.preferences = preferences
    self.contactStore = contactStore
    }

    @Published private var preferences: Preferences
    @Published private var contactStore: ContactStore

    var contactsAllImported: [Contact] { contactStore.contacts }

    func processAddressBookAndGoToNextScreen() {
    contactStore.requestAccessAndImportContacts() { didAllow in
    DispatchQueue.main.async {
    if didAllow {
    self.go(to: .relevantNewScreen)
    else { self.go(to: .relevantOtherScreen) }
    }
    }
    }

    ...
    }

    查看.swift
    struct SelectEasiestToCall: View {
    @EnvironmentObject var onboarding: OnboardingVM

    var body: some View {
    VStack {
    ForEach(onboarding.allContactsImported) { contact in
    SomeView(for: contact)
    }
    }

    最佳答案

    我假设您所说的不工作是指 ForEach不显示导入的联系人。
    问题是,当您为 ContactStore.contacts 分配新值时,这不会被检测为 OnboardingVM 中的更改. @Published房产 contactStore没有改变,因为它是 class - 引用类型。
    您需要做的是编写代码以手动响应此更改。
    您可以做的一件事是在添加新联系人时调用另一个处理程序,并在收到消息后调用 objectWillChange.send ,这会让观察者知道这个对象会改变(然后会重新计算它的主体)

    func processAddressBookAndGoToNextScreen() {
    contactStore.requestAccessAndImportContacts(
    onAccessResponse: { didAllow in
    ...
    },
    onContactsImported: {
    self.objectWillChange.send() // <- manually notify of change
    }
    )
    }
    (您显然需要对 requestAccessAndImportPhoneContactsimportContacts 进行一些修改才能真正调用我添加的 onContactsImported 处理程序)
    还有其他通知方法(例如使用委托(delegate))。
    您可以使用发布者进行通知,但在这里似乎没有用,因为这是一次性导入,而发布者/订阅者似乎有点过头了。

    关于ios - 如何在 SwiftUI 中进行异步更新后解雇发布者?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63542092/

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