Вставка коллекции Realm для обновления пользовательского интерфейса - PullRequest
0 голосов
/ 24 марта 2020

Если вы посмотрите документы Realm для Swift, раздел Запись с интерфейсом указывает, что вы можете наблюдать collection:

// Add fine-grained notification block
token = collection.observe { changes in
  switch changes {

  case .initial:
    tableView.reloadData()

  case .update(_, let deletions, let insertions, let modifications):
    // Query results have changed, so apply them to the UITableView
    tableView.beginUpdates()

    // Always apply updates in the following order: deletions, insertions, then modifications.
    // Handling insertions before deletions may result in unexpected behavior.
    tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}),
                          with: .automatic)
    tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }),
                          with: .automatic)
    tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }),
                          with: .automatic)
    tableView.endUpdates()

  case .error(let error):
    // handle error
    ()
  }
}

Я предполагаю, что это означает collection имеет тип Results<Item>!.

Но прямо под этим он демонстрирует способ выполнения write, позволяя пользовательскому интерфейсу обновляться мгновенно:

func insertItem() throws {
  // Perform an interface-driven write on the main thread, making sure 
  // the change notification doesn't apply the change a second time
  try collection.realm!.write(withoutNotifying: [token]) {
    collection.insert(Item(), at: 0)
  }

  // And mirror it instantly in the UI instead
  tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
}

Но что не имеет смысла в том, что в этом случае collection имеет метод insert, который недоступен для типа Results<Item>!, только для массива.

Существует ли тип, который может быть наблюдал и вставил? Если нет, то нужно ли мне управлять собственным массивом и поддерживать Results<Item>! в синхронизации c с моим собственным массивом [Item]?

1 Ответ

0 голосов
/ 25 марта 2020

Позвольте мне попытаться уточнить:

Существует два (или более) варианта обновления вашего пользовательского интерфейса. Я называю их «Вручную» и «Automati c».

1) «Вручную» - запишите данные в область, используя без уведомления, а затем вручную обновите свой пользовательский интерфейс. Это будет «мгновенно», поскольку вы контролируете, когда случается

2) Automati c - записывает данные в область, а затем позволяет наблюдателю на этих данных обновлять пользовательский интерфейс на основе события, возвращенного из области. Это будет «отложено», потому что это произойдет в зависимости от времени получения события. На практике Realm чертовски быстр, поэтому «задержка» обычно незаметна. Где это может быть более применимо, во время анимации пользовательского интерфейса, где вы хотите, чтобы они запускались немедленно, вместо того, чтобы немного подождать, прежде чем начать (1/2 секунды или меньше?)

Чтобы ответить на вопрос в комментарии

Всегда ли вы перемещаете свои результаты в массив [Person] (например), когда используете Realm?

Вы редко, если вообще когда-либо, «перемещаете» результаты в массив - или используйте функции Swift для работы с объектами области.

Объекты области загружаются лениво - поэтому, если в области есть 100 000 объектов, использующих функции области для работы с объектами, сортировка и фильтрация будут иметь минимальное влияние.

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

Так что взгляните на эту дополнительную причину, чтобы сохранить результаты как Результаты. Предположим, у вас есть объект области PersonClass, и вы хотите получить все объекты person, которые имеют имя Leroy.

Вот функции области

let realmResults = realm.objects(PersonClass.self).filter("first_name == 'Leroy'")
let realmResultsType = type(of: realmResults)
print(realmResultsType)

, а затем с помощью фильтра Swift

let swiftResults = realm.objects(PersonClass.self).filter { $0.first_name == "Leroy" }
let swiftResultsType = type(of: swiftResults)
print(swiftResultsType)

и затем вывод

Results<PersonClass>
LazyFilterSequence<Results<PersonClass>>

Вы заметите, что типы объектов различны. Если вы хотите добавить наблюдателя к этим объектам для отслеживания изменений, вы можете сделать это непосредственно с помощью области Результаты

self.notificationToken = self.realmResults!.observe { (changes: RealmCollectionChange) in

, но не с помощью LazyFilterSequence.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...