ios - 快速删除时,使用 Realm 的 Tableview 不会重新加载

标签 ios swift uitableview realm

我有一个带有已保存数据的简单 tableView。我创建了一个删除按钮,可以让我从 Realm 中进行多次删除。那部分有效,当 TableView 应该重新加载时,它似乎不起作用。我看到很多答案说你应该使用 dispatchQueue.main.async 在主线程上重新加载它,或者查看或其他什么 仅使用普通的 tableView.reloadData() 不会重新加载 tableview,但是当我使用 dispatchQueue 版本时,它会删除一个值,但通常是 tableView 中的最后一个值。

例如,我的 tableView 具有按降序排列的字符串 Uno 和 Un。如果我在按下删除按钮时选择删除 Uno,那么 tableview 会重新加载,只留下一个值,但该值是 Uno,但 realm Database 告诉我我删除了 Uno,当我返回该 View 时它显示 Un。它只是没有正确重新加载。

我已尝试将 reloadData 放置在许多不同位置的调度中,但它仍然无法正确重新加载。我很好奇我做错了什么。

这是带有 tableview 的 viewController,我在其中删除了 tableView 中的数据:

    import UIKit
import Realm
import RealmSwift

class OtherViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var otherTableView: UITableView!

    var realm: Realm!
    var realmedData = ""

    var realmList: Results<Realmed> {
        get {
            return realm.objects(Realmed.self)
        }
    }
    let deleteBtn = UIBarButtonItem()
    var testingBool = false
    var realmArr = [String]()
    var idValue = [Int]()
    var idArr = [Int]()

    var spanArrValue: [String] = []



    override func viewDidLoad() {
        super.viewDidLoad()
        otherTableView.reloadData()
        realm = try! Realm()
        self.otherTableView.delegate = self
        self.otherTableView.dataSource = self
        self.otherTableView.reloadData()
        deleteBtnInfo(btn: deleteBtn)
        self.navigationItem.rightBarButtonItem = deleteBtn
    }



    func deleteBtnInfo(btn: UIBarButtonItem) {
        btn.title = "Delete"
        btn.style = .plain
        btn.target = self
        btn.action = #selector(didTapDeleteBtn(sender:))
        testingBool = false

    }

    @objc func didTapDeleteBtn(sender: AnyObject) {
        testingBool = !testingBool
        if testingBool == true {
            deleteBtn.title = "Remove"
            otherTableView.allowsMultipleSelection = true
            otherTableView.allowsMultipleSelectionDuringEditing = true
        } else if testingBool == false {
            deleteBtn.title = "Delete"
            didPressRemove()
            DispatchQueue.main.async {
                self.otherTableView.reloadData()
            }
            otherTableView.allowsMultipleSelection = false
            otherTableView.allowsMultipleSelectionDuringEditing = false
        }
    }

    func didPressRemove() {
        if idValue.count == 0 {
            print("Please Select what to Delete")
        } else {
            deleteRealm(idInt: idValue)

        }
    }

    func deleteRealm(idInt: [Int]) {
        do {
            try realm.write {
                for deleteIndex in idInt {
                    let deleteValue = realm.objects(RealmTwo.self).filter("id == %@", deleteIndex as Any)
                    print(deleteIndex)
                    realm.delete(deleteValue)


                }

            }
        } catch {

        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        var counted = realm.objects(RealmTwo.self).filter("realmLbl == %@", realmedData)
        return counted.count

    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
        var celledItem = realm.objects(Realmed.self)
        for item in celledItem {
            for items in item.realmTwo {
                self.idArr.append(items.id)
                self.realmArr.append(items.spanish)
            }
        }
        cell.otherLbl.text = "\(realmArr[indexPath.row])"
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if testingBool == false {
            print(realmArr[indexPath.row])
        } else {
            self.idValue.append(idArr[indexPath.row])
            print(spanArrValue)
        }
    }


    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        if testingBool == true {
            if let index = idValue.index(of: idArr[indexPath.row]) {
                idValue.remove(at: index)
                print(spanArrValue)
            }
        }
    }
}

这是我要删除的数据的 Realm 类。

    import Foundation
import UIKit
import Realm
import RealmSwift

class RealmTwo: Object {
    @objc dynamic var id = Int()
    @objc dynamic var realmLbl = String()
    @objc dynamic var spanish = String()
    @objc dynamic var french = String()
    let realmed = LinkingObjects(fromType: Realmed.self, property: "realmTwo")



    convenience init(id: Int, realmLbl: String, spanish: String, french: String) {
        self.init()
        self.id = id
        self.realmLbl = realmLbl
        self.spanish = spanish
        self.french = french
    }

}

正如我上面所说,我将 reloadData() 放在不同的地方,这些是我放置它们的地方,以防万一你想知道:

 func didPressRemove() {
    if idValue.count == 0 {
        print("Please Select what to Delete")
    } else {
        deleteRealm(idInt: idValue)
        DispatchQueue.main.async {
            self.otherTableView.reloadData()
        }
    }
}


    func deleteRealm(idInt: [Int]) {
    do {
        try realm.write {
            for deleteIndex in idInt {
                let deleteValue = realm.objects(RealmTwo.self).filter("id == %@", deleteIndex as Any)
                print(deleteIndex)
                realm.delete(deleteValue)
                DispatchQueue.main.async {
                    self.otherTableView.reloadData()
                }

            }

        }
    } catch {

    }
}

我只是不确定 reloadData 应该去哪里,或者这是否是真正的问题。谢谢你的帮助,请问还有什么我可以做的。

最佳答案

有几个问题,但主要问题是您正在从 Realm 中删除该对象,但该对象仍在您的 dataSource tableView 数组 realmAr 中。

有一大堆解决方案,但最简单的是向 Realm 结果添加观察者,当添加、更改或删除项目时,更新数据源数组,然后重新加载 TableView 。这里还有一种选择是使用这些结果 作为数据源而不是单独的数组。 Realm Results 对象的行为与数组非常相似,非常适合作为数据源。

从概念上讲, Realm 代码类似于

notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in
    guard let tableView = self?.tableView else { return }
    switch changes {
    case .initial:
        tableView.reloadData() //this is when the realm data is intially loaded.
    case .update(_, let deletions, let insertions, let modifications):
        //handle add, edit and modify per event.
        // with an add, add the provided object to your dataSource
        // same thing for remove and modify
    case .error(let error):
        // An error occurred while opening the Realm file on the background worker thread
        fatalError("\(error)")
    }
    //reload the tableView now the dataSource has been updated
}

处理这些事件有多种选择,它们都包含在 Realm 文档中。参见 Realm Notifications有关设置通知的更多详细信息。

第二种选择是手动保持同步;例如从 Realm 中删除项目时,也从数据源数组中删除项目

关于ios - 快速删除时,使用 Realm 的 Tableview 不会重新加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53789298/

相关文章:

ios - 使用 Asset Catalog 在 Retina 显示器上加载非 Retina 图像

objective-c - 来自Twitter TWRequest处理程序的泄漏

ios - 如何将自定义类设置为以编程方式创建的 UIButton?

ios - 比较数组列表和选定值并根据索引将其显示在表格 View 单元格中

ios - SwiftUI 中月份的开始和结束日期

iphone - UITableViewCell 分配问题 - 单元格不为零

Swift - 在 UITableViewController 中通过 Storyboard 显示一个带有空列表的复杂 View

ios - AFNetworking 500 响应正文

ios - 如何在 SwiftUI 中对列表中的值求和?

ios - Tableview button.tag 抛出 lldb