我正在开发一个自动登录功能,在应用程序打开时,会运行一个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时使全屏覆盖消失。
1条答案
按热度按时间falq053o1#
在SwiftUI中,你可以使用带有
.task
修饰符的Task { }
/await。这是因为我们的View
结构是没有生命周期的简单值,所以你只是将它们触发到其中一个。通过使用.task
,生命周期与出现的东西/从屏幕上消失。你也不再需要onAppear
或ObservableObject
了。例如:字符串
同样在Swift和SwiftUI中,尽量在任何地方都坚持使用结构值类型,以防止一致性错误。