首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何为fetch设置完成处理程序(withQuery:,inZoneWith:) cloudKit func

如何为fetch设置完成处理程序(withQuery:,inZoneWith:) cloudKit func
EN

Stack Overflow用户
提问于 2022-03-29 20:46:24
回答 1查看 320关注 0票数 0

我正在开发一个使用cloudKit存储用户数据的存储管理系统。我在私有数据库中设置了一些预置数据的自定义区域。

我有一个func loadCustomerArray(),它应该检索"Customers“区域中的所有记录,然后从每个返回的CKRecord中创建一个Customer对象。我使用的是fetch(withQuery: , inZoneWith: )函数,但是由于没有关于这个函数的文档,而且对于这个问题的大多数在线回答都使用了现在不再推荐的方法,所以我很难为这个函数设置完成处理程序。

这是我的代码:

代码语言:javascript
运行
复制
func loadCustomerArray() async throws -> [Customer] {
    //set the cloud database to the users private database
    let cloudDB = CKContainer.default().privateCloudDatabase
    let custZone = CKRecordZone(zoneName: "Customers")
    
    let pred = NSPredicate(value: true) //true -> return all records
    let query = CKQuery(recordType: "Customer", predicate: pred)
    
    var customerRecords: [Customer] = []
    
    //Get the records matching these criteria
    cloudDB.fetch(withQuery: query, inZoneWith: custZone.zoneID, resultsLimit: 100) { result, error in
        
    }

    return customerRecords
}

目前,我得到了一个错误的Contextual closure type '(Result<(matchResults: [(CKRecord.ID, Result<CKRecord, Error>)], queryCursor: CKQueryOperation.Cursor?), Error>) -> Void' expects 1 argument, but 2 were used in closure body,但是我不知道用什么代替result, error in来迭代结果。

编辑

根据杰西的指示我放弃了那个想法。

以下是我对如何实现他的解决方案的理解:

我添加了func recordsqueryRecords func表单,相同的帖子如下所示:

代码语言:javascript
运行
复制
public func queryRecords(recordType: CKRecord.RecordType, predicate: NSPredicate, database: CKDatabase, Zone: CKRecordZone) async throws -> [CKRecord] {
    return try await database.records(type: recordType, predicate: predicate, zoneID: Zone.zoneID)
}

public extension CKDatabase {
/// Request `CKRecord`s that correspond to a Swift type.
///
/// - Parameters:
///   - recordType: Its name has to be the same in your code, and in CloudKit.
///   - predicate: for the `CKQuery`
func records(type: CKRecord.RecordType,predicate: NSPredicate = .init(value: true),zoneID: CKRecordZone.ID) async throws -> [CKRecord] {
try await withThrowingTaskGroup(of: [CKRecord].self) { group in
  func process(
    _ records: (
      matchResults: [(CKRecord.ID, Result<CKRecord, Error>)],
      queryCursor: CKQueryOperation.Cursor?
    )
  ) async throws {
    group.addTask {
      try records.matchResults.map { try $1.get() }
    }
    if let cursor = records.queryCursor {
      try await process(self.records(continuingMatchFrom: cursor))
    }
  }
  try await process(
    records(
      matching: .init(
        recordType: type,
        predicate: predicate
      ),
      inZoneWith: zoneID
    )
  )
    
    return try await group.reduce(into: [], +=)
  }
}
}

并向我的Customer类添加了一个初始化器,如下所示:

代码语言:javascript
运行
复制
//Initializer with CKRecord
init (record: CKRecord) {
    self.ID = record["customerID"] as! Int
    self.CustomerName = record["customerName"] as! String
    self.ContactName = record["contactName"] as! String
    self.Address = record["Address"] as! String
    self.City = record["City"] as! String
    self.PostalCode = record["postCode"] as! String
    self.Country = record["Country"] as! String
}

所以现在我的loadCustomerArray()功能是这样的:

代码语言:javascript
运行
复制
func loadCustomerArray() async throws -> [Customer] {
    //array to be returned
    var customers: [Customer] = []

    //set the cloud database to the users private database
    let cloudDB = CKContainer.default().privateCloudDatabase
    let custZone = CKRecordZone(zoneName: "Customers")
    
    let pred = NSPredicate(value: true) //true -> return all records
    
    //Get the records matching these criteria
    let customerRecords = try await queryRecords(recordType: "Customer", predicate: pred, database: cloudDB, Zone: custZone)
    
    for record in customerRecords {
        //create customer object from the records
        let customer = Customer(record: record)
        //add customer obj to the array to be returned
        customers.append(customer)
    }
    
    return customers
}

上述loadCustomerArray()`` func is called like so inside of my customers page viewDidLoad()` func:

代码语言:javascript
运行
复制
Task {
    do {
       customerArray = try await loadCustomerArray()
       tableView.reloadData()
    }
    catch {
        print(error)
    }
}

但是它仍然不能正常工作,所以对如何正确地实现它的任何解释都是非常有帮助的。

更新

我添加了以下代码,让用户知道他们的iCloud帐户是否可以在应用程序中使用:

代码语言:javascript
运行
复制
 //check iCloud acc. status
 CKContainer.default().accountStatus { (accountStatus, error) in
        //creates an alert popup depending on the iCloud account status
        switch accountStatus {
        case .available:
            let cloudAvailable = UIAlertController(title: "iCloud Account Available",
                                                   message: "your iCloud account will be used to store your stores data",
                                                   preferredStyle: .alert)
            cloudAvailable.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (_) in
                cloudAvailable.dismiss(animated: true)
            }))
            
            DispatchQueue.main.async {
                self.present(cloudAvailable, animated: true)
            }
            
            
        case .noAccount:
            let noCloud = UIAlertController(title: "No iCloud Account Available",
                                            message: "this app requires an iCloud account, please set up an account and then try to sign up again",
                                            preferredStyle: .alert)
            noCloud.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (_) in
                noCloud.dismiss(animated: true)
            }))
            
            DispatchQueue.main.async {
                self.present(noCloud, animated: true)
            }
            
            
        case .restricted:
            let restrictedCloud = UIAlertController(title: "iCloud Account Is Restricted",
                                                    message: "please unrestrict your iCloud account and try to sign up again",
                                                    preferredStyle: .alert)
            restrictedCloud.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (_) in
                restrictedCloud.dismiss(animated: true)
            }))
            
            DispatchQueue.main.async {
                self.present(restrictedCloud, animated: true)
            }
            
            
        //unable to determine iCloud Account status as the defualt case
        default:
            let unableToDetermine = UIAlertController(title: "Unable To Determine iCloud Account Status",
                                                      message: "please make sure you have set up an iCloud account and that it allows this app access",
                                                      preferredStyle: .alert)
            unableToDetermine.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (_) in
                unableToDetermine.dismiss(animated: true)
            }))
            
            DispatchQueue.main.async {
                self.present(unableToDetermine, animated: true)
            }
        }

在我注册页面的viewDidLoad()功能里面。当我在模拟器上测试它时,它返回了noCloud UIAlertController,所以问题是我没有在模拟器中登录我的Apple。

EN

Stack Overflow用户

发布于 2022-03-29 22:17:54

不要将旧API与Swift并发混用。相反,请将Customer与类似于InitializableWithCloudKitRecord的协议相结合。

代码语言:javascript
运行
复制
var customers: [Customer] {
  get async throws {
    try await .init(
      database: CKContainer.default().privateCloudDatabase,
      zoneID: CKRecordZone(zoneName: "Customers").zoneID
    )
  }
}
代码语言:javascript
运行
复制
public protocol InitializableWithCloudKitRecord {
  init(record: CKRecord) throws
}

public extension Array where Element: InitializableWithCloudKitRecord {
  init(
    database: CKDatabase,
    zoneID: CKRecordZone.ID? = nil,
    predicate: NSPredicate = .init(value: true)
  ) async throws {
    self = try await database.records(
      type: Element.self,
      zoneID: zoneID,
      predicate: predicate
    ).map(Element.init)
  }
}

The necessary records overload is here.

票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71668593

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档