I am trying to implement batch fetching to integrate with cloudkit and async display kit. However, when I try to scroll around, I get this error:
[NSOperationQueue addOperation:]: operation is finished and cannot be enqueued'
Any idea would this be happening? Thanks!
These are my networking calls:
var thisCursor : CKQueryCursor?
var newQueryOP : CKQueryOperation?
func pullPosts(curLocation: CLLocation, completionHandler: @escaping(([PostMap]) -> Bool)) {
print("------------PULLING POSTS (1ST PULL) ----------------")
let location = curLocation
var annotations : [PostMap] = [PostMap]()
//let curLocation = mapLocationManager.getCurrentLocation()
let locationPredicate = NSPredicate(format: "distanceToLocation:fromLocation:(%K, %@) < %f", "Location", location,
CKConstants.loadPinsRadius)
let query = CKQuery(recordType: "PostMap", predicate: locationPredicate)
query.sortDescriptors = [CKLocationSortDescriptor(key: "Location", relativeLocation: location)]
let queryOP = CKQueryOperation(query: query)
print("SERVER DECIDED QUERY LIMIT \(queryOP.resultsLimit)")
queryOP.recordFetchedBlock = { record in
//MAKE A NEW POST (taken out for brevity)
annotations.append(postToAdd)
}
queryOP.queryCompletionBlock = { [unowned self] (cursor, error) in
DispatchQueue.main.async {
if error == nil {
if completionHandler(annotations) {
if cursor != nil {
print("THIS CURSOR IS NOT NIL")
self.thisCursor = cursor
self.newQueryOP = CKQueryOperation(cursor: cursor!)
}
}
} else {
print(error)
print("could not pull posts")
}
}
}
queryOP.resultsLimit = 15
CKContainer.default().publicCloudDatabase.add(queryOP)
}
public func continuePullPosts(curLocation: CLLocation, queryOP: CKQueryOperation,
annotations: [PostMap], completionHandler: @escaping(([PostMap]) -> Bool)) {
var annotations = annotations
print("------------CONTINUE PULLING POSTS ----------------")
queryOP.recordFetchedBlock = { record in
//MAKE A NEW POST (taken out for brevity)
annotations.append(postToAdd)
}
queryOP.queryCompletionBlock = { [unowned self] (cursor, error) in
DispatchQueue.main.async {
if error == nil {
if completionHandler(annotations) {
if cursor != nil {
print("paging posts")
self.thisCursor = cursor!
self.newQueryOP = CKQueryOperation(cursor: cursor!)
}
}
} else {
print(error)
print("could not pull posts")
}
}
}
queryOP.resultsLimit = CKConstants.subsequentPullAmount
CKContainer.default().publicCloudDatabase.add(queryOP)
}
In my TableViewController:
func shouldBatchFetch(for tableNode: ASTableNode) -> Bool {
if (pinDataManager.thisCursor == nil) {
return false
}; return true
}
func tableNode(_ tableNode: ASTableNode, willBeginBatchFetchWith context: ASBatchContext) {
var annotations : [PostMap] = [PostMap]()
pinDataManager.continuePullPosts(curLocation: locationManager.getCurrentLocation(), queryOP: pinDataManager.newQueryOP!, annotations: annotations) { (annotations) -> Bool in
self.insertNewRowsInTableNode(annotations: annotations)
context.completeBatchFetching(true)
return true
}
}
func insertNewRowsInTableNode(annotations: [MapObject]) {
let section : NSInteger = 0
let indexPaths = NSMutableArray()
let totalPosts = self.postObjects.count + annotations.count
print(self.postObjects.count)
print(annotations.count)
for index in self.postObjects.count...totalPosts - 1 {
let path = NSIndexPath(row: index, section: section)
indexPaths.add(path)
}
self.postObjects = self.postObjects + annotations
self.tableNode.insertRows(at: indexPaths as! [IndexPath], with: .none)
}
You're passing a completed operation into your continuePullPosts
function, then attempting to re-add it to the database.
Instead, you need to save the cursor returned from the first operation, pass that cursor to continuePullPosts and then create a new follow-up operation using initWithCursor
.
You need to continue to create new operations with initWithCursor
every time you receive a cursor until the query eventually finishes and returns a nil cursor.