CloudKit私有AccountInfo引用公共Wine记录查询报错求解决方案
问题分析与解决方案
错误根源
你遇到的Custom zones are not allowed in public DB错误,核心原因是你尝试查询的CKRecordID带有私有数据库的自定义zone标识(zoneID=AccountInformation:defaultOwner)。这说明你从AccountInfo中取出的Wine引用,指向的是私有区的记录,而非你预期的公共库Wine记录——要么是创建引用时选错了记录,要么是Wine记录本身就误存到了私有区。
修正步骤与代码调整
1. 先确认数据正确性
打开CloudKit Dashboard检查:
- 公共数据库中是否存在目标Wine记录,且它们的
recordID使用默认根zone(无自定义zone标识)。 - 私有数据库中
AccountInfo的Wines字段,所有引用的recordID均对应公共库的Wine记录。
2. 修正UserObj初始化代码
替换强制解包为可选绑定(避免崩溃),并行查询提升效率,同时增加zone合法性校验:
public class UserObj: ObservableObject { var Fname: String var Lname: String var username: String var password: String var email: String var phoneNumber: String var pfp: UIImage @Published var wines: [Wine] = [] // 用@Published让UI感知数据更新 var recordID: String init(ckrecord: CKRecord) async throws { // 安全解析CKRecord字段 guard let fname = ckrecord["FName"] as? String, let lname = ckrecord["LName"] as? String, let username = ckrecord["Username"] as? String, let password = ckrecord["Password"] as? String, let email = ckrecord["Email"] as? String, let phoneNumber = ckrecord["PhoneNumber"] as? String, let imageAsset = ckrecord["PFP"] as? CKAsset, let imageURL = imageAsset.fileURL, let imageData = try? Data(contentsOf: imageURL), let pfp = UIImage(data: imageData) else { throw NSError(domain: "UserObjInit", code: -1, userInfo: [NSLocalizedDescriptionKey: "解析用户记录失败"]) } self.Fname = fname self.Lname = lname self.username = username self.password = password self.email = email self.phoneNumber = phoneNumber self.pfp = pfp self.recordID = ckrecord.recordID.recordName // 处理Wine引用列表 guard let wineRefs = ckrecord["Wines"] as? [CKRecord.Reference] else { return } let publicDB = CKContainer.default().publicCloudDatabase // 并行查询所有Wine记录 await withTaskGroup(of: Wine?.self) { group in for ref in wineRefs { group.addTask { do { // 校验引用的记录是否属于公共库根zone(公共库不允许自定义zone) guard ref.recordID.zoneID == CKRecordZone.default().zoneID else { print("无效引用:记录不在公共库根zone中,跳过 \(ref.recordID)") return nil } guard let fetchedRecord = try await publicDB.record(for: ref.recordID) else { print("未找到对应Wine记录:\(ref.recordID)") return nil } return try await Wine(ckrecord: fetchedRecord) } catch { print("获取Wine记录失败:\(error.localizedDescription)") return nil } } } // 收集有效Wine对象 for await wine in group { if let wine = wine { self.wines.append(wine) } } } } }
3. 修正Wine类初始化代码
同样优化数据解析逻辑,处理Vineyard引用:
class Wine: Identifiable { var type: String var vintage: String @Published var vineyard: Vineyard? // 用可选类型替代空对象初始化 let id: UUID init(ckrecord: CKRecord) async throws { guard let type = ckrecord["Type"] as? String, let vintage = ckrecord["Vintage"] as? String else { throw NSError(domain: "WineInit", code: -1, userInfo: [NSLocalizedDescriptionKey: "解析Wine记录失败"]) } self.type = type self.vintage = vintage self.id = UUID() // 处理Vineyard引用 if let vineyardRef = ckrecord["Vineyard"] as? CKRecord.Reference { let publicDB = CKContainer.default().publicCloudDatabase do { guard vineyardRef.recordID.zoneID == CKRecordZone.default().zoneID else { print("Vineyard引用无效:不在公共库根zone") return } guard let fetchedRecord = try await publicDB.record(for: vineyardRef.recordID) else { print("未找到对应Vineyard记录") return } self.vineyard = try Vineyard(ckrecord: fetchedRecord) } catch { print("获取Vineyard失败:\(error.localizedDescription)") } } } } // 示例Vineyard类(需根据你的实际字段调整) class Vineyard { var name: String? init() {} init(ckrecord: CKRecord) throws { self.name = ckrecord["Name"] as? String // 解析其他Vineyard字段 } }
内容的提问来源于stack exchange,提问作者JonGrimes20
相关产品推荐
相关产品推荐

