So I am building an iOS app working with CloudKit. A particular function calls for Products:
func getAllProducts(){
//empty object in Singleton Class
sharedStore.products.removeAllObjects()
var products = NSMutableArray()
//set up a query
var predicate = NSPredicate(value: true)
var query = CKQuery(recordType: "Product", predicate: predicate)
//set in query operation
var queryOperation = CKQueryOperation(query: query)
//define method to catch fetched records
//define completion block to process results
queryOperation.queryCompletionBlock = { (cursor: CKQueryCursor!, error: NSError!) in
if error != nil {
//there was an error, get this error to the delegate
self.delegate?.cloudKitReturnedError(error)
} else {
//there was no error
println("no error")
//cursor is used to know if there is more data to be fetched, so check cursor
if cursor != nil {
//there is more data to fetch
println("more data to be fetched")
//start new query
let newOperation = CKQueryOperation(cursor: cursor)
newOperation.completionBlock = queryOperation.completionBlock
newOperation.recordFetchedBlock = queryOperation.recordFetchedBlock
self.privateDB.addOperation(newOperation)
dispatch_async(dispatch_group_enter(<#group: dispatch_group_t#>), <#block: dispatch_block_t##() -> Void#>)
} else {
println("all data fetched")
self.delegate?.cloudKitReturnedArray!(products, identifier: "StoreProducts")
}
}
}
queryOperation.recordFetchedBlock = { (record: CKRecord!) in
let product = self.saveProduct(record)
if product.categoryReference == nil {
products.addObject(product)
}
}
//add the operation
self.privateDB .addOperation(queryOperation)
}
Please note that all CloudKit communication happens in a dedicated CloudKitController class.
When large stacks of data are to be fetched, it does not load them at once but 'activates' it's cursor. However, when it does so, it apparently calls dispatch_group_leave() somewhere in background. When it's cursor starts receiving data, and it completes, my queryCompletionBlock
is supposed to send a "finished" message to it's delegate, but instead I get this:
libdispatch.dylib`dispatch_group_leave:
0x1088edfd9 <+0>: movl $0x1, %eax
0x1088edfde <+5>: lock
0x1088edfdf <+6>: xaddq %rax, 0x40(%rdi)
0x1088edfe4 <+11>: incq %rax
0x1088edfe7 <+14>: js 0x1088edffe ; <+37>
0x1088edfe9 <+16>: movabsq $0x7fffffffffffffff, %rcx
0x1088edff3 <+26>: cmpq %rcx, %rax
0x1088edff6 <+29>: jne 0x1088edffd ; <+36>
0x1088edff8 <+31>: jmp 0x1088ee00e ; _dispatch_group_wake
0x1088edffd <+36>: retq
0x1088edffe <+37>: leaq 0x180c8(%rip), %rcx ; "BUG IN CLIENT OF LIBDISPATCH: Unbalanced call to dispatch_group_leave()"
0x1088ee005 <+44>: movq %rcx, 0x301a4(%rip) ; gCRAnnotations + 8
-> 0x1088ee00c <+51>: ud2
I suppose I should call dispatch_group_enter()
somehow in my code, but this whole asynchronous thing is new to me. I have read through Apple's documentation but I cannot manage to write a piece of code that does the job.
The question How do I prevent getting this Unbalanced call to "dispatch_group_leave()" when CloudKit works with a cursor to retrieve large stacks of data?
Any comments are highly appreciated.