簡體   English   中英

Realm Swift:Object已被刪除或失效

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM