ios 如何在swiftUI中重新加载视图

ds97pgxw  于 11个月前  发布在  iOS
关注(0)|答案(1)|浏览(136)

我正在开发一个自动登录功能,在应用程序打开时,会运行一个cloudkit查询来确定此设备是否具有已知的用户信息,然后将该信息加载到我的Model类中。
代码如下:

  • 葡萄酒应用程序 *
struct vinoApp: App {
//    @StateObject private var dataController = DataController()
    @ObservedObject var model = Model()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear(perform: {
                    Task {
                        do{
                            try await loadActiveUser()
                        }
                        catch {
                            print("Error: \(error)")
                        }
                    }
                })
        }
    }
    
    private func loadActiveUser() async throws {
        let record = try await queryUserRecord()
        if record != [] {
            //this line works
            model.activeUser = try await UserObj(ckrecord: record[0])
            model.userDoesntExist = false
        }
        else { model.activeUser = UserObj() }
    }
    
    /**
     Queries Account Info from private 'AccountInformation' Record Zone
     
     What does this mean?: Passing argument of non-sendable type 'NSPredicate' outside of main actor-isolated context may introduce data races
     */
    private func queryUserRecord() async throws -> [CKRecord] {
        let cloudDB = CKContainer.default().publicCloudDatabase
        let device = UIDevice.current.identifierForVendor
        
        //set pred
        let pred = NSPredicate(format: "LastKnownDevice == %@", device!.uuidString)
        print(device!.uuidString)
        let query = CKQuery(recordType: "AccountInfo", predicate: pred)
        //query public record
        let (userResults, _) = try await cloudDB.records(matching: query)
        //return the public CKRecord of the user
        return userResults.compactMap { _, result in
            guard let record = try? result.get() else { return nil }
            return record
        }
    }
}

字符串

  • 内容视图 *
struct ContentView: View {
    //State vars
    @ObservedObject var model = Model()
    
    var body: some View {
        VinoMainView()
        /**
         when app is opened we must evaluate if a user exists
         if user exists : model.userDoesntExits = false
         else : model.userDoesntExits = true
         */
            .fullScreenCover(isPresented: $model.userDoesntExist, content: {
                NavigationStack {
                    ZStack {
                        LoginForm()
                        NavigationLink(
                            "Dont Have an Account? Sign-Up Here",
                            destination: SignUpView(
                                userNotSignedin: $model.userDoesntExist
                            )
                        )
                            .font(.custom("DMSerifDisplay-Regular", size: 15))
                            .padding([.top], 300)
                        //Add loading view here?
                    }
                }
            })
        }
    /**
     check if user exists in privateDB zone
     -also sets active user to the user found
     */
    func checkIfUserDoesntExists() -> Bool {
        //if the array of CKRecords returned by 'queryUserRecords()' is not empty -> userDoesntExist = false
        if model.activeUser.isEmpty() {
            //create UserObj from record[0] because the private account zone queried from should only have one record
            //MARK: need to reload views
            return true
        }
        else { return false }
    }
}

  • 型号 *
class Model: ObservableObject {
    @Published var activeUser = UserObj()
    @Published var userDoesntExist = true
}


我知道实际的查询正在工作,因为当我调试它时,我可以在deugger中看到这样的结果:

我可以看到model.userDoesntExist也发生了变化,像这样:

尽管我可以看到代码在大部分情况下都在工作,但ContentView中的fullScreenCover仍然显示,所以我想知道如何刷新ContentView,以便在model.userDoesntExist设置为false时使全屏覆盖消失。

falq053o

falq053o1#

在SwiftUI中,你可以使用带有.task修饰符的Task { }/await。这是因为我们的View结构是没有生命周期的简单值,所以你只是将它们触发到其中一个。通过使用.task,生命周期与出现的东西/从屏幕上消失。你也不再需要onAppearObservableObject了。例如:

struct vinoApp: App {

    @State var config = Config()

    var body: some Scene {
        WindowGroup {
            ContentView(config: config)
                .task {
                    do{
                        config.error = nil
                        config.user = try await loadActiveUser()
                    }
                    catch {
                        print("Error: \(error)")
                        config.error = error
                    }
                }
        }
    }

字符串
同样在Swift和SwiftUI中,尽量在任何地方都坚持使用结构值类型,以防止一致性错误。

相关问题