两个CloudKit可以互相调用死锁吗?如何修复



在一个performQuery内部,正在调用另一个performQuery。两者的recordType参数相同,但predicate参数不同。

第二个performQuery永远不会返回,应用程序只是运行并等待CloudKit响应。

伪代码如下:

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)

这看起来像是一个信号量线程问题。您正在重用sama参数。最后一个dispatch_semaphore_signal必须移动到else内部的上方。然后可以完全去除第一个dispatch_semaphore_wait。所以它将是这样的:

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)

死锁是这样修复的:内部查询在外部查询之后移动。两个信号灯都保留了。外部完成处理程序在内部完成处理程序启动之前完成。从CloudKit返回的记录存储在本地变量中。

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

最新更新