gpt4 book ai didi

ios - 在后台删除的数据导致 UITableView 中的索引超出范围崩溃

转载 作者:行者123 更新时间:2023-11-28 08:59:30 25 4
gpt4 key购买 nike

代码

var animals: Results<Animal> {
didSet {
self.tableView.reloadData()
}
}

问题

  • 我有一个 UITableView显示动物列表
  • 我还有一个定期同步 Animals 列表的后台进程
  • 显示 UITableView 的 UIViewController 通过成员变量跟踪 Animals。
  • 如果后台进程在我查看列表时从 Realm DB 中删除了最后一个 Animal,则 animals集合更新,但 UITableView不知道它丢失了一行,如果我滚动到已删除的 Animal 所在的位置,我会收到来自 Realm 的边界索引异常并且应用程序崩溃。

尝试过的解决方案

  1. 我试图复制 Results<Animal>进入[Animal]在内存中并绑定(bind) UITableView相反,因为 Array不会像 Results<Animal> 那样自动刷新确实(没有办法将其关闭,对吗?)。这解决了 Index out of bounds 异常,除了现在我收到一个异常,用于访问已删除/无效对象的属性,因为当单元格读取已删除对象的属性时,它必须返回 Realm。不会去上类。
  2. 然后我尝试收听 Realm 的通知和 .reloadData表相应。这可行,但会导致过多的表重新加载并增加确保通知 token 被释放等的开销,并记住在应用程序中的所有 TableView 中执行此操作。

解决方法

我最终创建了一个 RealmTableHandler单例,基本上是解决方案 #2 的改进版本。

public extension UITableView {
public func addToRealmTableHandler() {
RealmTableHandler.sharedInstance.addTrackedTable(self)
}
}

/// Listens for Realm Notifications and reloads tracked UITableViews if needed
public class RealmTableHandler {
public static let sharedInstance = RealmTableHandler()

private var notificationToken: NotificationToken!

private var tableIdentifier = 0
private lazy var trackedTables = NSMapTable(keyOptions: NSHashTableWeakMemory, valueOptions: NSHashTableWeakMemory)
private lazy var trackedDelegates = NSMapTable(keyOptions: NSHashTableWeakMemory, valueOptions: NSHashTableWeakMemory)
private lazy var trackedDatasources = NSMapTable(keyOptions: NSHashTableWeakMemory, valueOptions: NSHashTableWeakMemory)

private init() {
self.startListening()
}

private func startListening() {
self.notificationToken = Realm().addNotificationBlock { (notification, realm) -> Void in
self.checkTrackedTables()
}
}

public func addTrackedTable(table: UITableView) {
if self.trackedTables.count == 0 {
self.tableIdentifier = 0
}

if let delegate = table.delegate, datasource = table.dataSource {
self.tableIdentifier++

self.trackedTables.setObject(table, forKey: self.tableIdentifier)
self.trackedDelegates.setObject(delegate, forKey: self.tableIdentifier)
self.trackedDatasources.setObject(datasource, forKey: self.tableIdentifier)
}
}

private func checkTrackedTables() {
// Ensure table, delegate, datasource are all available, sometimes the delegate or datasource are deallocated before the table, but the table keeps a reference to them
for key in self.trackedTables.keyEnumerator().allObjects {
if let table = self.trackedTables.objectForKey(key) as? UITableView,
delegate = self.trackedDelegates.objectForKey(key) as? UITableViewDelegate,
datasource = self.trackedDatasources.objectForKey(key) as? UITableViewDataSource
{
// Check if tracked tables need to be reloaded due to Realm data changes
let numSectionsInTableView = table.numberOfSections()
var numRowsInTableView = 0
let numSectionsInDatasource = datasource.numberOfSectionsInTableView?(table) ?? numSectionsInTableView
var numRowsInDatasource = 0

if numSectionsInTableView <= 0 || numSectionsInDatasource <= 0 {
return
}

for i in 0...(numSectionsInTableView - 1) {
numRowsInTableView += table.numberOfRowsInSection(i)
}
for i in 0...(numSectionsInDatasource - 1) {
numRowsInDatasource += datasource.tableView(table, numberOfRowsInSection: i)
}

if numRowsInTableView != numRowsInDatasource {
table.reloadData()
}
}
}
}
}

然后我将以下代码添加到任何 UITableViews如果 Realm 增加或减少行数,我想重新加载。

self.tableView.addToRealmTableHandler()

这似乎工作正常,即使是分段的 UITableViews (只要分段数据也是 Results<T> )。

有没有更好/更简单的方法来解决这个问题?

Realm 以后会支持表的插入/删除吗?

最佳答案

(免责声明:我为 Realm 工作。)

Hrmm,听起来您想要类似于 Core Data 中的 NSFetchedResultsController 的东西,在添加/删除对象时,您可以在其中获得一组通用级别但细粒度的通知。

我不确定这是否能解决您的问题,但实际上有一个开源库旨在通过名为 RBQFetchedResultsController ( https://github.com/Roobiq/RBQFetchedResultsController ) 的 Realm 来做到这一点。至少,这应该有助于避免您尝试自己创建自定义解决方案。 :)

如果这能解决您的问题,请告诉我!

关于ios - 在后台删除的数据导致 UITableView 中的索引超出范围崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32278224/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com