Realm Swift: объект был удален или признан недействительным - PullRequest
0 голосов
/ 29 мая 2020

У меня есть tableViewController (ArticlesV C), который отображает массив статей, полученных из API. Каждая из этих tableViewCell имеет кнопку «Дополнительные действия», которая позволяет пользователю сохранить статью для последующего чтения в SavedV C. Обратите внимание, что в Realm DB записываются только сохраненные статьи, отображение статей в статьяхV C не записывается в Realm DB.

Если пользователь сохранил статью, я бы показал «Удалить сохраненную статью» в противном случае я показываю «Сохранить на потом». Я прошу Realm провести эту проверку.

Однако, если я удалю сохраненную статью (или все сохраненные статьи) из Realm из SavedV C и go обратно в ArticlesV C и начну прокручивать tableView, произойдет сбой с указанной выше ошибкой . Эта ошибка sh происходит периодически, поэтому ее довольно сложно определить.

Код

//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)")
        }
    }
}

Я предполагаю, что из-за того, что я удалил статьи в SavedV C, но Статьи V C по-прежнему указывает на те объекты Realm, которые больше не существуют и поэтому разбились.

Я прочитал несколько сообщений SO, в которых предлагается выполнить проверку obj.isInvalidated, что я сделал и включил условие для этого. Но это все равно вылетает.

Другие попытки включают:

  • с использованием realm.create() вместо realm.add()

1 Ответ

0 голосов
/ 29 мая 2020

Вот проблема: вы сохранили неуправляемый объект (статью) в области

func getAction(article: Article)
    ...
    self.saveArticle(article: article)

, что затем делает его управляемым объектом.

Если он удален из области,

realm.delete(article)

он также будет удален из объекта результатов, который его содержит

articles[indexPath.row]

, что затем заставит ваше приложение sh, поскольку оно прокручивается, поскольку dataSource и tableView не синхронизируются c.

У меня такое чувство, что вы не хотите, чтобы он действительно был удален из основного списка статей.

Я предлагаю сохранить любые статьи, которые вы хотите прочитать позже, их идентификатор, который не будет влиять на главный список статей, когда они добавляются и удаляются из области.

Другими словами, ваш главный список статей остается прежним, но в Realm у вас есть таблица идентификаторов, которые например, строки. Итак, если вы хотите отслеживать, что они хотят прочитать,

self.saveArticleId(article: article.id)

, а затем, когда пришло время удалить это из их сохраненного списка чтения

self.deleteArticleBy(articleId: artical.id)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...