如何检测两个不同的查询,然后在swift中调用另一个函数?

时间:2016-06-07 02:53:24

标签: ios swift semaphore dispatch

我的函数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

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

     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()
        }
    }

答案 2 :(得分:1)

基于@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 :(得分:0)

感谢所有答案。我不得不最终混合了一些东西才能使它工作,因为这里值得分享。

我必须添加dispatch_group_enterdispatch_group_leave才能在运行cloudkit查询时停止它。

这很奇怪,因为它只运行了dispatch_group_enterdispatch_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)