嵌套 Cloudkit 查询未按正确顺序打印

Posted

技术标签:

【中文标题】嵌套 Cloudkit 查询未按正确顺序打印【英文标题】:Nested Cloudkit queries not printing in the right order 【发布时间】:2020-09-15 15:35:24 【问题描述】:

我的代码打印顺序不正确。我认为这是我使用 dispatch to main 的方式的问题。我想传递一个老板ID。找到具有该 ID 的用户,然后获取他们的订阅老板数组。对于该数组中的每个 ID,查询该用户并返回该用户 screenName。将这些屏幕名称附加到 userArray。之后完成 GetBossSubs 函数并返回 userArray(screenNames 数组)。

现在.onAppear 的结果在.onAppear 中的函数实际完成之前运行。 User AppendedFound TestUserName 之前打印

static func getBossSubs(bossID: String, completion: @escaping (Result<UserNames, Error>) ->
    ()) 
    let pred = NSPredicate(format: "uniqueID = %@", bossID)
    let sort = NSSortDescriptor(key: "creationDate", ascending: false)
    let query = CKQuery(recordType: RecordType.Users, predicate: pred)
    query.sortDescriptors = [sort]
    
    let operation = CKQueryOperation(query: query)
    operation.desiredKeys = ["subscribedBosses"]
    operation.resultsLimit = 50
    
    operation.recordFetchedBlock =  record in
        DispatchQueue.main.async 
            guard let subs = record["subscribedBosses"] as? [String] else 
                print("Error at screenName")
                
                completion(.failure(CloudKitHelperError.castFailure))
                return
            
            let userArray = UserNames() //Error that it should be a LET is here. 
            for boss in subs
                CloudKitHelper.getBossScreenName(bossID: boss)  (result) in
                    
                    switch result
                        
                    case .success(let name):
                        userArray.names.append(name) //works fine
                        print("Found \(userArray.names)") //Prints a name
                    case .failure(let er):
                        completion(.failure(er))
                    
                    
                
                
                
            
            print("does this run?") // Only runs if No Name
            completion(.success(userArray)) // contains no name or doesn't run?
        
    
    operation.queryCompletionBlock =  (_, err) in
        DispatchQueue.main.async 
            if let err = err 
                completion(.failure(err))
                return
            
        
        
    
    CKContainer.default().publicCloudDatabase.add(operation)

我这样称呼代码:

.onAppear 
            // MARK: - fetch from CloudKit
            self.userList.names = []
            let myUserID = UserDefaults.standard.string(forKey: self.signInWithAppleManager.userIdentifierKey)!
            // get my subs projects
            CloudKitHelper.getBossSubs(bossID: myUserID)  (results) in
                switch results
                    
                case .success(let user):
                    print("Users appended")
                    self.userList.names = user.names
                case .failure(let er):
                    print(er.localizedDescription)
                
            
        

【问题讨论】:

【参考方案1】:

这是因为您在另一个异步函数中运行了一个异步函数。

// this just *starts* a series of asynchronous functions, `result` is not yet available
for boss in subs 
    CloudKitHelper.getBossScreenName(bossID: boss)  result in
        switch result 
        case .success(let name):
            userArray.names.append(name) // works fine
            print("Found \(userArray.names)") // Prints a name
        case .failure(let er):
            completion(.failure(er))
        
    


// this will run before any `CloudKitHelper.getBossScreenName` finishes
completion(.success(userArray))

一种可能的解决方案可能是检查所有CloudKitHelper.getBossScreenName 函数是否完成(例如,通过检查userArray 的大小),然后才返回完成:

for boss in subs 
    CloudKitHelper.getBossScreenName(bossID: boss)  result in
        switch result 
        case .success(let name):
            userArray.names.append(name)
            if userArray.names.count == subs.count 
                completion(.success(userArray)) // complete only when all functions finish
            
        case .failure(let er):
            completion(.failure(er))
        
    


// do not call completion here, wait for all functions to finish
// completion(.success(userArray))

【讨论】:

所以我需要在 for 循环内部添加第二个完成(.success())?它也被附加了,所以我想我需要看看之前的计数 + subs.count == 当前的计数。 for 循环下方的完成在任何 CloudKitHelper.getBossScreenName 完成之前触发。您需要按照上面的示例移动它。你的情况应该只有一个completion(.success()) 哦,这就是为什么你让它等于潜艇的数量!

以上是关于嵌套 Cloudkit 查询未按正确顺序打印的主要内容,如果未能解决你的问题,请参考以下文章

Firebase iOS 查询未按预期排序

嵌套查询未按预期工作

嵌套 CloudKit 查询和 UITableView

CKReference 的 CloudKit 订阅通知未按预期工作

CLGeoCoder 未按正确顺序附加地标

条带 webhook 未按正确顺序传入的错误