简体   繁体   中英

Can two CloudKit call deadlock each other? How to fix?

Inside a performQuery an other performQuery is being called. The recordType arguments are same for both, but the predicate s are different.

The second performQuery never returns, the App just runs and waits for CloudKit to respond.

The pseudo code is like this:

publicDatabase.performQuery(CKQuery(recordType: recordTypeSrc, predicate: predicate), inZoneWithID: nil, completionHandler: {records, error in

    if error == nil {

        //.. problem is not name collision or reusing the same parameter, coming codepart is called though other methods

        publicDatabase.performQuery(CKQuery(recordType: recordTypeSrc, predicate: predicate2), inZoneWithID: nil, completionHandler: {records, error in

            //THIS LINE WILL NEVER GET REACHED

            if error == nil {

            } else {
                println(error.localizedDescription)
            }
            dispatch_semaphore_signal(sema2)
        })
        dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER)

        //..

    } else {
        println(error.localizedDescription)
    }
    dispatch_semaphore_signal(sema)
})
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)

It looks like a semaphore threading issue. You are reusing the sama parameter. The last dispatch_semaphore_signal must be moved to above inside the else. Then the first dispatch_semaphore_wait can be removed completely. So it will be like this:

publicDatabase.performQuery(CKQuery(recordType: recordTypeSrc, predicate: predicate), inZoneWithID: nil, completionHandler: {records, error in

    if error == nil {

        //.. problem is not name collision, it is nested though other blocks

        publicDatabase.performQuery(CKQuery(recordType: recordTypeSrc, predicate: predicate2), inZoneWithID: nil, completionHandler: {records, error in

            //THIS LINE WILL NEVER GET REACHED

            if error == nil {

            } else {
                println(error.localizedDescription)
            }
            dispatch_semaphore_signal(sema)
        })

        //..

    } else {
        println(error.localizedDescription)
        dispatch_semaphore_signal(sema)
    }
})
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)

Deadlock was fixed like this: Inner query moved after outer query. Both semaphore retained. Outer completion handler is finished before inner completion handler would start. From CloudKit returned records are stored in local variables.

var records: [AnyObject]! = []
publicDatabase.performQuery(CKQuery(recordType: recordTypeSrc, predicate: predicate), inZoneWithID: nil, completionHandler: {records2, error in

    if error == nil {
        records = records2
    } else {
        println(error.localizedDescription)
    }
    dispatch_semaphore_signal(sema)
})
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)

//HERE I can use records

var records3: [AnyObject]! = []
publicDatabase.performQuery(CKQuery(recordType: recordTypeSrc, predicate: predicate2), inZoneWithID: nil, completionHandler: {records4, error in

    if error == nil {
        records3 = records4
    } else {
        println(error.localizedDescription)
    }
    dispatch_semaphore_signal(sema2)
})
dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER)

//HERE I can use records3 too

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM