【问题标题】:How to detect two different queries are completed to then call another function in swift?如何检测两个不同的查询完成然后快速调用另一个函数?
【发布时间】:2016-06-07 02:53:24
【问题描述】:

我的函数runsQueries 运行两个不同的查询。在调用updateResults 函数之前,我需要完成这两个查询。

完成它的最佳方法是什么?我尝试了一些不同的方法,但到目前为止都没有真正奏效。

    func runsQueries(){

    var foundRecords = [CKRecords]()

    let notified = dispatch_semaphore_create(0)
    let group = dispatch_group_create()
    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

    dispatch_group_async(group, queue) {
        // query 1
        let predicate1 = NSPredicate(format: "userID = %@", user1ID)
        let cloudKitQuery1 = CKQuery(recordType: "Messages", predicate: predicate1)
        publicDatabase.performQuery(cloudKitQuery1, inZoneWithID: nil) { (messageRecords: [CKRecord]?, error: NSError?) in
            if error != nil
            {
                    print("-> cloudKitLoadMessage - userID1 error \(error)")
            }
            else
            {
                     print("-> cloudKitLoadMessage - user1Done - message") 
                     foundRecords.apend(messageRecords[0])
            }
        }

        // query 2
        let predicate2 = NSPredicate(format: "userID = %@", user2ID)
        let cloudKitQuery2 = CKQuery(recordType: "Messages", predicate: predicate2)
        publicDatabase.performQuery(cloudKitQuery2, inZoneWithID: nil) { (messageRecords: [CKRecord]?, error: NSError?) in
            if error != nil
            {
                    print("-> cloudKitLoadMessage - userID2 error \(error)")
            }
            else
            {
                     print("-> cloudKitLoadMessage - user2Done - message")
                     foundRecords.apend(messageRecords[0])  
            }
        }
    }

    dispatch_group_notify(group, queue) {
            // This block will be executed when all tasks are complete
          print("All tasks complete")
          dispatch_semaphore_signal(notified)
    }

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
    dispatch_semaphore_wait(notified, DISPATCH_TIME_FOREVER)
    print("Semaphore done")

        // only call updateResults when queries 1 and 2 are done
        updateResults(foundRecords)

   }

第二个功能

func updateResults(messageRecords: [CKrecord]){

  // do something now that you got both messages  

}

基于来自https://gist.github.com/nbhasin2/735cd80298b5d47852f2的一些想法

【问题讨论】:

    标签: ios swift semaphore dispatch


    【解决方案1】:

    使用“Dispatch Gruop”并将两个查询放在两个不同的调度块中。

    看到这个答案: https://stackoverflow.com/questions/11909629/waiting-until-two-async-blocks-are-executed-before-starting-another-block

    【讨论】:

      【解决方案2】:

      基于@christian mini 的回答:

      dispatch_group_t group = dispatch_group_create();
      
      dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
              // query 1
          let predicate1 = NSPredicate(format: "userID = %@", user1ID)
          let cloudKitQuery1 = CKQuery(recordType: "Messages", predicate: predicate1)
          publicDatabase.performQuery(cloudKitQuery1, inZoneWithID: nil) { (messageRecords: [CKRecord]?, error: NSError?) in
              if error != nil
              {
                      print("-> cloudKitLoadMessage - userID1 error \(error)")
              }
              else
              {
                       print("-> cloudKitLoadMessage - user1Done - message") 
                       foundRecords.apend(messageRecords[0])
              }
          }
      });
      
      
      dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
              // query 2
          let predicate2 = NSPredicate(format: "userID = %@", user2ID)
          let cloudKitQuery2 = CKQuery(recordType: "Messages", predicate: predicate2)
          publicDatabase.performQuery(cloudKitQuery2, inZoneWithID: nil) { (messageRecords: [CKRecord]?, error: NSError?) in
              if error != nil
              {
                      print("-> cloudKitLoadMessage - userID2 error \(error)")
              }
              else
              {
                       print("-> cloudKitLoadMessage - user2Done - message")
                       foundRecords.apend(messageRecords[0])  
              }
          }
       });
      
      dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
              // only call updateResults when queries 1 and 2 are done
          updateResults(foundRecords) 
      }); 
      

      无论如何,您应该将查询块代码分离为一个函数。您的代码重复。

      【讨论】:

        【解决方案3】:

        可能有更优雅的解决方案,但我已经很好地使用了这种模式:

             func runsQueries(){
        
                var foundRecords = [CKRecords]()
        
                var query1Finished = false
                var query2Finished = false
        
                let updateResultsIfNeeded {
                    if query1Finished && query2Finished {
                        updateResults(foundRecords)
                    }
                }
        
                // query 1
                let predicate1 = NSPredicate(format: "userID = %@", user1ID)
                let cloudKitQuery1 = CKQuery(recordType: "Messages", predicate: predicate1)
                publicDatabase.performQuery(cloudKitQuery1, inZoneWithID: nil) { (messageRecords: [CKRecord]?, error: NSError?) in
                    if error != nil
                    {
                        print("-> cloudKitLoadMessage - userID1 error \(error)")
                    }
                    else
                    {
                        print("-> cloudKitLoadMessage - user1Done - message")
                        foundRecords.apend(messageRecords[0])
                    }
        
                    query1Finished = true
                    updateResultsIfNeeded()
                }
        
                // query 2
                let predicate2 = NSPredicate(format: "userID = %@", user2ID)
                let cloudKitQuery2 = CKQuery(recordType: "Messages", predicate: predicate2)
                publicDatabase.performQuery(cloudKitQuery2, inZoneWithID: nil) { (messageRecords: [CKRecord]?, error: NSError?) in
                    if error != nil
                    {
                        print("-> cloudKitLoadMessage - userID2 error \(error)")
                    }
                    else
                    {
                        print("-> cloudKitLoadMessage - user2Done - message")
                        foundRecords.apend(messageRecords[0])
                    }
        
                    query2Finished = true
                    updateResultsIfNeeded()
                }
            }
        

        【讨论】:

        • 查询完成后如何回调'updateResultsIfNeeded'?
        【解决方案4】:

        感谢您的所有回答。我最终不得不混合一些东西来让它工作,认为值得在这里分享。

        我必须添加 dispatch_group_enter 和 dispatch_group_leave 才能让它在运行 cloudkit 查询时停止。

        这很奇怪,因为它在没有 dispatch_group_enter 和 dispatch_group_leave 的情况下运行,如果它只运行下面的代码:

        let timeInterval = Double(arc4random_uniform(1000)) * 0.01
                NSThread.sleepForTimeInterval(timeInterval)
        

        还添加了一个for 循环以运行最多 4 个查询。尝试使用 ID 数组创建 for 并获得无限数量的查询,但它使 ID 无序,我需要它们按顺序排列。可以用字典试试。

        let notified = dispatch_semaphore_create(0)
        let group = dispatch_group_create()
        let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
        
        for n in 1..<5 {
        
            dispatch_group_async(group, queue) {
                dispatch_group_enter(group)
        
                print("nnnn \(n)")
        
                var userID = String()
                switch n {
                case 1:
                    userID = user1ID
                case 2:
                    userID = user2ID
                case 3:
                    userID = user3ID
                case 4:
                    userID = user4ID
                default:
                    print("")
                }
        
                var predicate = NSPredicate()
                predicate = NSPredicate(format: "userID = %@ AND chatRoomReference = %@", userID, roomReference)
                let cloudKitQuery = CKQuery(recordType: "Messages", predicate: predicate)
                let sort = NSSortDescriptor(key: "date", ascending: false)
                cloudKitQuery.sortDescriptors = [sort]
                publicDatabase.performQuery(cloudKitQuery, inZoneWithID: nil) { (messageRecords: [CKRecord]?, error: NSError?) in
        
                    // result in here
        
                switch n {
                case 1:
                    user1Dic = userDic
                case 2:
                    user2Dic = userDic
                case 3:
                    user3Dic = userDic
                case 4:
                    user4Dic = userDic
                default:
                    print("")
                }
                    dispatch_group_leave(group)
                }
            }
        }
        
        dispatch_group_notify(group, queue) {
            print("All tasks complete")
            dispatch_semaphore_signal(notified)
        }
        
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
        print("All tasks dispatch_group_wait")
        
        dispatch_semaphore_wait(notified, DISPATCH_TIME_FOREVER)
        print("All tasks dispatch_semaphore_wait")
        
        // that is when I return the results from all queries
        updateResults(error: nil, user1Dic: user1Dic, user2Dic: user2Dic, user3Dic: user3Dic, user4Dic: user4Dic)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-07
          • 2021-11-01
          • 1970-01-01
          • 2020-03-03
          • 2018-07-10
          • 1970-01-01
          相关资源
          最近更新 更多