Reputation: 2154
I am currently setting up CloudKit as a replacement to Parse and need to download all of my user records. I currently have around 600 records but I am only receiving 300.
I'm using a custom record zone called "User" rather than the default "Users" record zone as this app will only ever be tied to one appID.
The code I am using is based on the answer to the below question but it's not working for me. It seems that the query operation does not run when the cursor is nil as the print(userArray) is never called. Thanks in advance for your help!
CKQuery from private zone returns only first 100 CKRecords from in CloudKit
func queryAllUsers() {
let database = CKContainer.defaultContainer().privateCloudDatabase
let query = CKQuery(recordType: "User", predicate: NSPredicate(value: true))
let queryOperation = CKQueryOperation(query: query)
queryOperation.recordFetchedBlock = self.createUserObject
queryOperation.queryCompletionBlock = { cursor, error in
if cursor != nil {
print("there is more data to fetch")
let newOperation = CKQueryOperation(cursor: cursor!)
newOperation.recordFetchedBlock = self.createUserObject
newOperation.queryCompletionBlock = queryOperation.queryCompletionBlock
database.addOperation(newOperation)
} else {
print(userArray) //Never runs
}
}
database.addOperation(queryOperation)
}
func createUserObject(record: CKRecord) {
let name = record.objectForKey("Name") as! String!
let company = record.objectForKey("Company") as! String!
let dateInductionCompleted = record.objectForKey("DateInductionCompleted") as! NSDate!
var image = UIImage()
let imageAsset = record.objectForKey("Image") as! CKAsset!
if let url = imageAsset.fileURL as NSURL? {
let imageData = NSData(contentsOfURL:url)
let mainQueue = NSOperationQueue.mainQueue()
mainQueue.addOperationWithBlock() {
image = UIImage(data: imageData!)!
userArray.append(User(name: name, company: company, image: image, dateInductionCompleted: dateInductionCompleted))
}
}
print(userArray.count)
}
UPDATE
The question has been answered, it was possibly an inherent bug when using a cursor for large queries. The code now works by using a recursive function, working code below:
func queryRecords() {
let database = CKContainer.defaultContainer().privateCloudDatabase
let query = CKQuery(recordType: "User", predicate: NSPredicate(value: true))
let queryOperation = CKQueryOperation(query: query)
queryOperation.qualityOfService = .UserInitiated
queryOperation.recordFetchedBlock = populateUserArray
queryOperation.queryCompletionBlock = { cursor, error in
if cursor != nil {
print("There is more data to fetch")
self.fetchRecords(cursor!)
}
}
database.addOperation(queryOperation)
}
func fetchRecords(cursor: CKQueryCursor?) {
let database = CKContainer.defaultContainer().privateCloudDatabase
let queryOperation = CKQueryOperation(cursor: cursor!)
queryOperation.qualityOfService = .UserInitiated
queryOperation.recordFetchedBlock = populateUserArray
queryOperation.queryCompletionBlock = { cursor, error in
if cursor != nil {
print("More data to fetch")
self.fetchRecords(cursor!)
} else {
print(userArray)
}
}
database.addOperation(queryOperation)
}
func populateUserArray(record: CKRecord) {
let name = record.objectForKey("Name") as! String!
let company = record.objectForKey("Company") as! String!
let dateInductionCompleted = record.objectForKey("DateInductionCompleted") as! NSDate!
var image = UIImage()
let imageAsset = record.objectForKey("Image") as! CKAsset!
if let url = imageAsset.fileURL as NSURL? {
let imageData = NSData(contentsOfURL:url)
let mainQueue = NSOperationQueue.mainQueue()
mainQueue.addOperationWithBlock() {
image = UIImage(data: imageData!)!
userArray.append(User(name: name, company: company, image: image, dateInductionCompleted: dateInductionCompleted))
}
}
print(userArray.count)
}
Upvotes: 2
Views: 1203
Reputation: 13127
Could you try setting:
queryOperation.qualityOfService = .UserInitiated
This will indicate that your user interaction requires the data. Otherwise it could happen that de request is ignored completely.
As discussed below the actual answer was that you should not re-use completion blocks. Instead you should create a recursive function for fetching the next records from a cursor. A sample of that can be found at: EVCloudKitDao
Upvotes: 4