我正在开发自动登录功能,在应用程序打开时,会运行 cloudkit 查询来确定该设备是否具有已知的用户信息,并将该信息加载到我的模型类中。
这是代码:
维诺应用程序
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
}
我知道实际的查询正在工作,因为当我调试它时,我可以在调试器中看到如下结果:
我可以看到
model.userDoesntExist
也发生了变化,如下所示:
尽管我可以看到代码大部分都在工作,但
fullScreenCover
中的 ContentView
仍然显示,所以我想知道如何刷新 ContentView
以使全屏覆盖在 model.userDoesntExist
消失后消失设置为 false。
在 SwiftUI 中,您将 async/await 与
.task
修饰符 sp 一起使用,您不再需要 onAppear
或 ObservableObject
。例如
struct vinoApp: App {
@State var config = Config()
var body: some Scene {
WindowGroup {
ContentView()
.task {
do{
config.error = nil
config.user = try await loadActiveUser()
}
catch {
print("Error: \(error)")
config.error = error
}
}
}
}