Realm Swift: результаты получают уведомления, даже если данные не меняются (Swift) - PullRequest
0 голосов
/ 04 июня 2018

У меня есть модель с именем CardDetails

public class CardDetails: Object {

  @objc public dynamic var id : Int = 0
  @objc public dynamic var number : String?
  @objc public dynamic var name : String?
  @objc public dynamic var status : String?

    override public static func primaryKey() -> String? {
      return "id"
    }

    override public static func indexedProperties() -> [String] {
      return ["status"]
    }
}

Объект записывается в фоновом потоке, когда мы выбираем данные из API

let realm = try Realm()
try realm.write {
  for card in cardsList {
    realm.add(card,update: true)
  }
}

Я использовал NotificationToken следующим образом вViewController

var cardResults: Results<CardDetails>!
override func viewDidLoad() {
  super.viewDidLoad()       
  cardResults = realm.objects(CardDetails.self).filter("status = %@", "ACTIVE")
  tokenCards = cardResults.observe { [weak self] (changes: RealmCollectionChange) in
    switch(changes) {
    case .initial, .update:
      self?.setUpCardUI()
    case .error(let error):
            // An error occurred while opening the Realm file on the background worker thread
      fatalError("\(error)")
    }
  }
}

Проблема в том, что я получаю вызов setUpCardUI при каждом вызове конечной точки получения карты, хотя данные не изменены (активна только одна карта!).Это приводит к неожиданному поведению пользовательского интерфейса.

Ответы [ 3 ]

0 голосов
/ 25 декабря 2018

Это один из больших недостатков царства.Вот как это выглядит в моем случае: enter image description here

Что происходит:

1) Я извлекаю существующие в области данные и показываю их.
2) Загрузите новые данные с сервера.
3) Приходит те же данные, но область по-прежнему отправляет изменения об изменениях в своем уведомлении.
Из-за этого tableView подскакивает, когда данные возвращаются с сервера и уведомлениеблок запущен.

Есть проблемы с областями по этому поводу: https://github.com/realm/realm-java/issues/5451, https://github.com/realm/realm-core/issues/2787, https://github.com/realm/realm-cocoa/issues/3489

0 голосов
/ 12 марта 2019

Realm всегда будет отправлять изменения модификации при обновлении объекта, независимо от того, изменились ли данные, но это не значит, что мы не можем решить проблему и даже реализовать некоторые приятные улучшения.

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

import UIKit

// RealmDiff is just a lightweight struct to make passing the changes around cleaner
// public struct RealmDiff {
//    let deletions: [Int]
//    let insertions: [Int]
//    let modifications: [Int]
//}

extension UITableView {
    func reload(section: Int = 0, with diff: RealmDiff?, update: ((UITableViewCell, IndexPath) -> Void)? = nil) {
        guard let diff = diff else {
            reloadData()
            return
        }

        beginUpdates()
        insertRows(at: diff.insertions.map({ IndexPath(row: $0, section: section) }), with: .automatic)
        deleteRows(at: diff.deletions.map({ IndexPath(row: $0, section: section) }), with: .automatic)

        guard update != nil else {
            reloadRows(at: diff.modifications.map({ IndexPath(row: $0, section: section) }), with: .fade)
            endUpdates()
            return
        }

        endUpdates()

        let indexPaths = diff.modifications
            .map ({ IndexPath(row: $0, section: 0) })
            .filter { indexPathsForVisibleRows?.contains($0) ?? false }

        indexPaths.forEach {
            if let cell = cellForRow(at: $0) {
                update?(cell, $0)
            }
        }
    }
}

По умолчанию это по-прежнему будет обменивать все ячейки, что, вероятно, будет вызывать скачки в табличном представлении в зависимости от вашей реализации макета.Но мы также можем передать закрытие, чтобы вручную изменить данные в ячейке.Вот пример используемого расширения:

tableView.reload(with: diff) { [weak self] cell, indexPath in
    if let cell = cell as? MyCellClass {
        MyCellClass.configure(cell: cell, with: myDataSourceDataArray[indexPath.row], delegate: self)
    }
}

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

0 голосов
/ 04 июня 2018

вы пытались установить для обновления значение false и обновить интерфейс после завершения записи.

let realm = try Realm()
try realm.write {
  for card in cardsList {
    realm.add(card,update: false)
 }
 //Perhaps try updating the UI when it finished writing to realm
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...