Фон
В моем приложении я храню несколько идентификаторов объектов. Я использую эти идентификаторы для выполнения пакетных вызовов API. API ограничивает каждый вызов до 10 идентификационных номеров. Эти данные отображаются в UITableView. Пользователь может добавлять и удалять объекты, что добавляет или удаляет идентификатор объекта из базы данных.
Я использую базу данных Firestore для хранения идентификаторов объектов на моем конце.
Текущая реализация
Вот то, что я реализовал до сих пор, но оно вызывает сбой приложения при добавлении и удалении объектов. Я не смог понять, как правильно обращаться с этими случаями и является ли это правильным способом сделать что-то подобное.
- Получить идентификаторы объектов, которые будут использоваться для вызовов API
var objectIds: [String] = []
var chunkedObjectIds: [[String]] = []
var objects: [Array] = []
var offset: Int = 0
override func viewDidLoad() {
super.viewDidload()
getObjectIds()
}
func getObjectIds() {
// get objects IDs and store then in objectIds from the Firestore database
// setup the .addSnapshotLister so the query is triggered whenever there is a change in the data on Firestore for the collection
return chunkedObjectIds
// when finished, get the first 10 objects from the 3rd party API
fetchObjects()
}
- Возьмите массив идентификаторов объектов, разбейте его на массивы массивов (много по 10) и выполните вызов API для первых 10
func fetchObjects() {
// split objectIds array in array of arrays, in lots of 10
// chunkedObjectIds is set here
// request the objects for the first 10 ID numbers
Alamofire.request(… parameter with first 10 object ids …) (objects) in {
// save objects
// increment the offset
offset += 1
}
}
Визуализация данных в ячейках UITableView
Используйте следующий метод для загрузки дополнительных данных из стороннего API:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let lastRow = objects.count
var parameters = [String: Any]()
if indexPath.row == lastRow {
if !(offset == self.chunkedObjectIds.count) {
// process the next batch from the array
parameters["id-numbers"] = self.chunkedObjectIds[offset].map{String($0)}.joined(separator: ",")
Alamofire.request(… paramaters: parameters) { (objects) in
for item in 0..<objects.count {
let indexPath = IndexPath(row: item + self.objects.count, section: 0)
self.paths.append(indexPath)
}
self.objects.append(contentsOf: objects)
self.tableView.beginUpdates()
self.tableView.insertRows(at: self.paths, with: .automatic)
self.tableView.endUpdates()
self.paths.removeAll()
self.offset += 1
}
}
}
}
Добавление или удаление объектов:
- Идентификатор объекта добавляется или удаляется из базы данных Firestore
- ObjectIds, chunkedObjectIds, смещение и объекты очищаются
- Слушатель запускает чтение данных, и процесс повторяется
Проблема и вопрос
Это хорошо работает для загрузки исходных данных. Но при добавлении происходит дублирование (и иногда сбой). При удалении приложения происходит сбой из-за исключений вне диапазона.
Это правильный шаблон для использования в первую очередь? Если да, то что мне не хватает для обработки дел после первой загрузки, в частности, добавления и удаления новых идентификаторов объектов.
Редактировать
Я изменил реализацию на основе отзывов в комментариях. Итак, теперь процесс выглядит так:
- Настройка прослушивателя для получения данных из Firestore
- Цикл по идентификаторам объектов из Firestore, и пока счетчик <10 или мы достигаем object.count - Теперь я сохраняю следующее смещение, и в следующий раз, когда он вызывает этот метод, я запускаю цикл из следующего смещения с тем же в то время как условия </li>
- Извлечение объектов из стороннего API
- Я продолжал использовать метод
willDisplay cell
для запуска загрузки большего количества данных - казалось, он работал более надежно, чем метод scrollDidEnd
.
Так что теперь приложение больше не падает. Есть некоторые проблемы со слушателем Firestore, но я опубликую это как отдельный вопрос.