【发布时间】:2020-05-29 14:10:19
【问题描述】:
我有一个 tableViewController (ArticlesVC),它显示从 API 获取的文章数组。这些 tableViewCell 中的每一个都有一个“更多操作”按钮,允许用户保存文章以供以后在 SavedVC 中阅读。请注意,只有保存的文章会写入 Realm DB,ArticlesVC 中显示的文章不会写入 Realm DB。
如果用户保存了文章,我会显示“删除保存的文章”,否则,我会显示“稍后保存”。我查询 Realm 进行此检查。
但是,如果我从 SavedVC 的 Realm 中删除已保存的文章(或所有已保存的文章)并返回到 ArticlesVC 并开始滑动 tableView,它会因上述错误而崩溃。这种崩溃是间歇性发生的,因此很难确定。
代码
//At ArticlesVC, where articles are fetched via API
func getArticles() {
AF.request(apiUrl).responseJSON { (response) in
//Error checks and decoding ...
self.articles = try decoder.decode(Article.self, from: data)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ArticleCell
cell.article = articles[indexPath.row]
cell.moreButton.tag = indexPath.row
cell.moreButton.addTarget(self, action: #selector(moreButtonTapped(sender:)), for: .touchUpInside)
return cell
}
@objc func moreButtonTapped(sender: UIButton) {
let buttonTag = sender.tag
let article = articles[buttonTag]
let alert = UIAlertController(title: "More", message: nil, preferredStyle: .actionSheet)
let action = getAction(article: article)
alert.addActions([action, .cancelAction()])
//present alert
}
func getAction(article: Article) -> UIAlertAction {
do {
let realm = try Realm()
let articleInRealm = realm.objects(Article.self).filter("id == %@", article.id)
if articleInRealm.isInvalidated {
return UIAlertAction(title: "Save for later", style: .default, handler: {(_) in
self.saveArticle(article: article)
})
} else {
if articleInRealm.count == 0 {
return UIAlertAction(title: "Save for later", style: .default, handler: {(_) in
self.saveArticle(article: article)
})
} else {
return UIAlertAction(title: "Remove saved article", style: .destructive, handler: {(_) in
self.deleteArticle(article: articleInRealm)
})
}
}
} catch {
Log("Err getting article: \(error.localizedDescription)")
return UIAlertAction(title: "Save for later", style: .default, handler: {(_) in
self.saveArticle(article: article)
})
}
}
func saveArticle(article: Article) {
do {
let realm = try Realm()
try realm.write {
realm.add(article, update: .modified)
}
} catch {
Log("Err saving article: \(error.localizedDescription)")
}
}
func deleteArticle(article: Results<Article>) {
do {
let realm = try Realm()
try realm.write {
realm.delete(article)
}
} catch {
Log("Err saving article: \(error.localizedDescription)")
}
}
//At SavedVC, which is another VC in the tabBarController.
//ArticlesVC is in tab1 and SavedVC is in tab2
var notificationToken: NotificationToken? = nil
var articles: Results<Article>?
override func viewDidLoad() {
super.viewDidLoad()
subscribeToRealmNotifications()
}
fileprivate func subscribeToRealmNotifications() {
let realm = try! Realm()
let results = realm.objects(Article.self)
notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in
guard let tableView = self?.tableView else { return }
switch changes {
case .initial:
self?.articles = results
tableView.reloadData()
case .update(_, _, _, _):
tableView.reloadData()
case .error(let error):
fatalError("Realm notif: \(error.localizedDescription)")
}
}
}
我的猜测是,因为我已经删除了 SavedVC 中的文章,但 ArticlesVC 仍然指向那些不再存在并因此崩溃的 Realm 对象。
我已经阅读了多篇建议对obj.isInvalidated 进行检查的 SO 帖子,我已经这样做了,并且为此添加了一个条件。但这仍然崩溃。
其他尝试包括:
- 使用
realm.create()代替realm.add()
【问题讨论】:
-
几件事。领域结果对象是实时更新列表 - 如果从领域中删除一个对象,该结果列表也将被删除。这个函数定义有点麻烦
func deleteArticle(article: Results<Article>)好像你打算删除一篇文章,为什么要传入一个从技术上讲可能不止一个对象的结果对象?