Мы используем Realm
(Swift привязка в настоящее время в версии 3.12.0
) с самых первых дней в нашем проекте. В некоторых ранних версиях до 1.0
Realm
предусмотрены прослушиватели изменений для Results
без предоставления наборов изменений.
Мы использовали это много, чтобы узнать, изменился ли конкретный список Results
.
Позже ребята из Realm
обменялись этим API с методами предоставления changeSet. Мы должны были переключиться и теперь плохо обращаемся с этим API только для того, чтобы узнать, изменилось ли что-либо в определенном списке (вставки, удаления, модификации).
Вместе с RxSwift
мы написали собственную реализацию Results
прослушивания изменений, которая выглядит следующим образом:
public var observable: Observable<Base> {
return Observable.create { observer in
let token = self.base.observe { changes in
if case .update = changes {
observer.onNext(self.base)
}
}
observer.onNext(self.base)
return Disposables.create(with: {
observer.onCompleted()
token.invalidate()
})
}
}
Когда мы теперь хотим получать последовательные обновления в списке, мы подписываемся так:
someRealm.objects(SomeObject.self).filter(<some filter>).rx.observable
.subscribe(<subscription code that gets called on every update>)
//dispose code missing
Мы написали расширение для RealmCollection
, чтобы мы могли подписаться и на тип List
.
Концепция равна подходу RxRealm
.
Так что теперь в нашем приложении у нас есть много отфильтрованных списков / результатов, на которые мы подписываемся.
Когда данных становится все больше, мы замечаем значительные потери производительности, когда дело доходит до визуального изменения после записи чего-либо в БД.
Например:
Допустим, у нас есть класс Car
Realm Object с некоторыми свойствами и некоторыми отношениями 1-к-n и некоторыми 1-к-1. Одним из свойств является Bool
, а именно isDriving
.
Теперь у нас есть много автомобилей, хранящихся в БД, и множество слушателей изменений с различными фильтрами, перечисляющими изменения коллекции автомобилей (наблюдатели коллекции слушают changeSets, чтобы узнать, был ли изменен список).
Если я беру одну машину из какого-то списка и устанавливаю свойство isDriving
с false
на true
(важно: мы делаем записи в фоновом режиме ), в идеале слушатель изменений запускается быстро, и у меня есть почти немедленный правильный ответ на мою запись в основном потоке .
Добавлено с правкой на 2019-06-19:
Давайте сделаем сценарий еще более реальным:
Давайте изменим что-то по иерархии, скажем, название производителя шин. Скажем, Car
имеет List<Tire>
, Tire
имеет Manufacturer
и Manufacturer has a
имя .
Now we're still listing to
Результаты collection changes with some more or less complex filters applied.
Then we're changing the name of a
Изготовитель`, который подключен к одной из шин, подключенных к одной из автомобили, которые находятся в этом фильтрованном списке.
Может ли это все еще быть быстро?
Очевидно, что когда длина результатов / списков, к которым прикреплены прослушиватели изменений, становится больше, внутреннему прослушивателю изменений 1062 * требуется больше времени для вычисления различий и запускается позже.
Поэтому после записи мы видим изменения - в худшем случае - гораздо позже.
В нашем случае это неприемлемо. Итак, мы думаем о разных сценариях.
Один из сценариев состоит в том, чтобы больше не использовать .observe
в списках / результатах и переключаться на Realm.observe
, который срабатывает каждый раз, когда что-либо менялось в области, что не идеально, но это быстро, потому что процесс расчета изменений пропускается.
Мой вопрос: что я могу сделать, чтобы решить всю эту дилемму и снова сделать наше приложение быстрым?
Важнейшая вещь - это многопоточность. Мы всегда пишем в фоновом режиме из-за нашего дизайна. Таким образом, запись сама по себе должна быть очень быстрой, но тогда все это нужно синхронизировать с другими потоками, где открыты области.
В моем понимании, это происходит после того, как обнаружение изменений для всех Результатов прошло, правильно?
Поэтому, когда я читаю в другом потоке, данные обновляются только после синхронизации потока, которая происходит после отправки всех уведомлений. Но я не уверен в настоящее время, если синхронизация произойдет раньше, это было бы более круто, не проверял это сейчас.