Пакетная загрузка с помощью облачного набора

Можно ли реализовать "пакетную выборку" в cloudkit, чтобы я мог вызвать метод для извлечения следующих X записей? В настоящее время, согласно CloudKit Batch Fetches? CloudKit обрабатывает это неявно, но я хотел бы как-то создать метод, который позволяет мне каждый раз получать определенное количество запросов. Вот что у меня есть: (где continuePullPosts - метод, аналогичный тому, который я опубликовал)

queryOP.recordFetchedBlock = { record in
        //do stuff here
        annotations.append(postToAdd)
    }

    queryOP.queryCompletionBlock = { [unowned self] (cursor, error) in
        DispatchQueue.main.async {
            if error == nil {
                if completionHandler(annotations) {
                    if cursor != nil {
                        let newQueryOP = CKQueryOperation(cursor: cursor!)
                        self.continuePullPosts(curLocation: curLocation, queryOP: newQueryOP,
                                               annotations: annotations, completionHandler: completionHandler)
                    }
                }
            } else {
                print(error)
                print("could not pull posts")
            }
        }
    }

    queryOP.resultsLimit = CKQueryOperationMaximumResults
    CKContainer.default().publicCloudDatabase.add(queryOP)
}

1 ответ

Решение

Вы должны установить предел результата с желаемым значением вместо CKQueryOperationMaximumResultsпостоянное значение.

Я рекомендую определить обработчик завершения с параметрами для CKRecord результаты и CKQueryCursor, Этот обработчик завершения должен вызываться в queryCompletionBlock обработчик вашей CKQueryOperation.

После того, как ваш обработчик вызван, вы можете обработать результаты, и если курсор не равен NULL, это означает, что есть еще результаты для извлечения.

Это может быть что-то подобное

// Completion Handler (closure) definition
public typealias YourFetchCompletionHandler = (_ records: [CKRecords]?, cursor: CKQueryCursor?) -> (Void)

А вот функция, где вы выбираете записи

public func fetchYourRecords(_ cursor: CKQueryCursor? = nil, completionHandler handler: @escaping YourFetchCompletionHandler) -> Void
{
    var result: [CKRecord] = [CKRecord]()

    let queryOP: CKQueryOperation

    if let cursor = cursor
    {
        // Operation to fetch another 10 records.
        queryOP = CKQueryOperation(cursor: cursor)
    }
    else
    {
        // Create the operation for the first time
        queryOP = CKQueryCursor(query:...)
    }

    queryOp.recordFetchedBlock = { (record: CKRecord) -> Void in
        result.append(record)
    }

    queryOP.queryCompletionBlock = { [unowned self] (cursor, error) in
        handler(result, cursor)    
    }

    // Fetch only 10 records
    queryOP.resultsLimit = 10
    CKContainer.default().publicCloudDatabase.add(queryOP)
}

После вызова этой функции вы можете сохранить курсор, возвращенный в замыкании, в переменную, если она не равна нулю, для повторного вызова функции для восстановления следующих 10 записей.

Итак, ответ @Adolfo дал мне 95% пути, но у меня была одна проблема:

Каждый раз, когда я достигал последней страницы (или пакета) или данных, он просто начинал отправлять мне данные с начала моего набора данных.

Это было проблемой, потому что после того, как у меня закончились данные, я хотел, чтобы загрузка остановилась.

Чтобы исправить это, я добавил аргумент, чтобы указать, была ли это первая выборка или нет. Это позволило мне создать новый запрос только при первой выборке. Если бы это была не первая выборка, новый запрос не производился бы и был бы возвращен пустой массив.

public func fetchYourRecords(isFirstFetch: Bool, _ cursor: CKQueryCursor? = nil, completionHandler handler: @escaping YourFetchCompletionHandler) -> Void {
    var result: [CKRecord] = [CKRecord]()
    let queryOP: CKQueryOperation
    
    if isFirstFetch {
        // Create the operation for the first time

        queryOP = CKQueryCursor(query:...)
    } else if let cursor = cursor {
        // Operation to fetch another 10 records.

        queryOP = CKQueryOperation(cursor: cursor)
    } else {
        // If not first time and if cursor is nil (which means
        // there is no more data) then return empty array
        // or whatever you want

        handler([], nil)
        return
    }

    queryOp.recordFetchedBlock = { (record: CKRecord) -> Void in
        result.append(record)
    }

    queryOP.queryCompletionBlock = { [unowned self] (cursor, error) in
        handler(result, cursor)    
    }

    // Fetch only 10 records
    queryOP.resultsLimit = 10
    CKContainer.default().publicCloudDatabase.add(queryOP)
}
Другие вопросы по тегам