领域使用UICollectionView进行观察-竞赛条件

时间:2018-07-30 16:32:22

标签: ios swift uicollectionview realm

我正在使用Realm作为缓存层,以便无论何时将数据呈现给用户,都首先从数据库中获取数据并显示给用户。随后,发送服务器请求以获取数据的最新版本,将其与Realm数据库同步,并在UICollectionView中显示更改。

问题在于,当从Realm数据库中检索缓存的数据并且UICollectionView正在更新时,服务器的更新请求有可能在UICollectionView之前完成加载了所有单元格,并且由于Results列表是实时数据集合,因此可以对其进行修改。现在,例如,如果在服务器端删除了一项,则实时集合将保留少一项,因此会导致超出范围的异常。

话虽如此,考虑到Realm可以在results请求每一行时更改UITableView的事实,即使是官方class ViewController: UITableViewController { var notificationToken: NotificationToken? = nil override func viewDidLoad() { super.viewDidLoad() let realm = try! Realm() let results = realm.objects(Person.self).filter("age > 5") // Observe Results Notifications notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in guard let tableView = self?.tableView else { return } switch changes { case .initial: // Results are now populated and can be accessed without blocking the UI tableView.reloadData() case .update(_, let deletions, let insertions, let modifications): // Query results have changed, so apply them to the UITableView tableView.beginUpdates() tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }), with: .automatic) tableView.deleteRows(at: deletions.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): // An error occurred while opening the Realm file on the background worker thread fatalError("\(error)") } } } deinit { notificationToken?.invalidate() } } 文档中提供的代码也不是线程安全的一位:

tableView.endUpdates()

我想解决此问题的唯一方法是创建结果的深层副本,并使用Semaphore或类似方法同步观察函数的主体,以确保数据不会处于不一致的状态,我考虑效率很低。 (请注意,UITableView并不意味着@ToString(includeFieldNames=true) @EqualsAndHashCode @AllArgsConstructor public class PartyDTO<DATE> implements MongoDTO { @PersistenceConstructor public PartyDTO() { } @Id @Getter @Setter @Searchable private String partyId; @Getter @Setter private Meta<DATE> meta; @Getter @Setter @Searchable private String customerType; @Getter @Setter private PartyIdList idList; @Getter @Setter private String fullName; @Getter @Setter private PartyPerson<DATE> person; @Getter @Setter @Searchable private String branchId; @Getter @Setter @Searchable private String clientStanding; @Getter @Setter private ZonedDateTime clientStandingDate; @Getter @Setter private Boolean dayTraderInd; @Getter @Setter private List<PartyAltId> altIds; @Getter @Setter private List<PartyAltName> altNames; @Getter @Setter private List<Phone> phoneList; @Getter @Setter private List<NetContact> netContactList ; @Getter @Setter private List<Address> addressList; @Getter @Setter private PartySuitability<?> suitability; @Getter @Setter private List<PartyPref> prefList; } 已经重新加载了所有数据,但是只是将其分派到队列中并准备以异步方式进行处理。)

我想听听有关如何以有效方式实施此建议以消除上述比赛条件的任何建议。

2 个答案:

答案 0 :(得分:1)

您需要在主线程上进行所有UI更新。如果这样做,则第一组结果将更新主线程上的集合视图,当下一组结果也出现时,它将在主线程上排队,以便在完成第一组结果后进行更新。

答案 1 :(得分:0)

基于:

  

问题是,当从Realm数据库中检索缓存的数据并且UICollectionView得到更新时,服务器的更新请求有可能在UICollectionView加载所有单元之前完成,并且因为“结果”列表是实时的数据收集,可能已经被修改了。

我不认为会发生这种情况,因为一旦您的实时馆藏发生变化,就会触发更新通知,并且馆藏将相应地重建/更新。但是,正如我在PM中对您所说的那样,是我前一段时间与领域合作的时候。

检验您的假设非常容易:降低模拟器的互联网速度,或腾大桌子等等。我真的很好奇您是否能真正创建自己认为会遇到的问题。