Realm Swift:即使没有数据更改,结果也会收到通知(Swift)

时间:2018-06-04 03:39:03

标签: ios swift realm

我有一个名为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)
  }
}

我在ViewController中使用了NotificationToken,如下所示

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,虽然数据没有改变(只有一个活动卡!)。这导致意外的UI行为。

3 个答案:

答案 0 :(得分:0)

您是否已尝试将更新设置为false并在写入完成后更新UI。

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
}

答案 1 :(得分:0)

这是该领域的一大弊端。在我的情况下是这样的: enter image description here

发生了什么事

1)我获取领域数据中的现有数据并进行显示。
2)从服务器加载新数据。
3)带有SAME数据,但领域仍会在其通知中发送修改更改。
因此,当数据从服务器返回并触发通知块时,tableView会跳起来。

存在以下领域问题:https://github.com/realm/realm-java/issues/5451https://github.com/realm/realm-core/issues/2787https://github.com/realm/realm-cocoa/issues/3489

答案 2 :(得分:0)

无论数据是否更改,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)
    }
}

这样,您使用的是同一单元,不需要重新加载。我发现这种方法非常有效,并且非常可重用。