[英]Realm Swift: Object has been deleted or invalidated
我有一個 tableViewController (ArticlesVC),它顯示從 API 獲取的文章數組。 這些 tableViewCell 中的每一個都有一個“更多操作”按鈕,允許用戶保存文章以供以后在 SavedVC 中閱讀。 注意,只有保存的文章寫入 Realm DB,ArticlesVC 中的文章顯示不寫入 Realm DB。
如果用戶保存了文章,我會顯示“刪除保存的文章”,否則,我會顯示“稍后保存”。 我查詢 Realm 進行此檢查。
但是,如果我從 SavedVC 的 Realm 和 go 中刪除已保存的文章(或所有已保存的文章)回到 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()
這是問題所在:您已將非托管 object(文章)保存到 realm
func getAction(article: Article)
...
self.saveArticle(article: article)
然后使其成為托管 object。
如果從 Realm 中刪除,
realm.delete(article)
它也將從包含它的結果 object 中刪除
articles[indexPath.row]
這將使您的應用程序崩潰,因為它正在滾動,因為 dataSource 和 tableView 不同步。
我有一種感覺,您不希望它實際上從文章主列表中刪除。
我的建議是保存您以后想要閱讀的任何文章,因為它們在 realm 中添加和刪除時對文章的主列表沒有影響。
換句話說,您的文章主列表保持不變,但在 Realm 中,您有一個 id 表,例如字符串。 因此,當您想跟蹤他們想閱讀的內容時
self.saveArticleId(article: article.id)
然后是時候從他們保存的閱讀列表中刪除它
self.deleteArticleBy(articleId: artical.id)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.