1

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)
}
Shekar
  • 240
  • 1
  • 5
  • 14

1 Answers1

1

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.

Thunk
  • 4,099
  • 7
  • 28
  • 47
  • This worked! My next question would be that when I'm scrolling through the feed (powered by Texture), the batch fetching seems to reposition where I am on the feed as it populates the feed some more. Is there any way to prevent this, to make the scrolling a smooth process? Does it have something to do with at what point I start the batch fetch? Thanks! – Shekar Mar 10 '18 at 21:09
  • I'm not familiar with Texture. You'll probably get more folks to see your followup question (and therefore more likely fo find someone familiar with that library) if you create second question specifying that symptom in the title. – Thunk Mar 11 '18 at 00:08