【问题标题】:Tableview using realm won't reload when deleted in swift使用领域的表格视图在快速删除时不会重新加载
【发布时间】:2018-12-15 03:33:47
【问题描述】:

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

例如,我的 tableView 具有按降序排列的字符串 Uno 和 Un。如果我在按下删除按钮时选择删除 Uno,tableview 会重新加载,只留下一个值,但该值是 Uno,但领域数据库告诉我我删除了 Uno,当我返回该视图时,它显示 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)
            }
        }
    }
}

这是我要删除的数据的领域类。

    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 应该去哪里,或者这是否是真正的问题。谢谢你的帮助,请问我还有什么可以做的。

【问题讨论】:

    标签: ios swift uitableview realm


    【解决方案1】:

    有几个问题,但主要问题是您正在从领域中删除对象,但该对象仍然在您的 dataSource tableView 数组中徘徊,realmArr

    有很多解决方案,但最简单的方法是将观察者添加到领域结果中,当添加、更改或删除项目时,更新您的 dataSource 数组,然后重新加载 tableview。这里的一种选择是使用 这些结果 作为数据源,而不是单独的数组。 Realm Results 对象的行为与数组非常相似,并且非常适合作为数据源。

    从概念上讲,领域代码类似于

    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 中删除项目时,还要从 dataSource 数组中删除项目

    【讨论】:

    • 这是个好主意,但没有奏效。它所做的只是崩溃,消息是 Invalid update: invalid number of rows in section 0。更新 (5) 后现有部分中包含的行数必须等于该部分中包含的行数之前update (5),加上或减去从该节插入或删除的行数(1 插入,0 删除),加上或减去移入或移出该节的行数(0 移入,0 移出)。 '
    • @NEWBY 我的答案中的代码没有崩溃;崩溃的是 tableView 委托方法。原因是如何处理数组。在 tableView 获取要显示的行数的代码中,计数来自这个 var counted = realm.objects(RealmTwo.self)。但是,当 tableView 获取要显示的实际数据时,它会尝试从此 var celledItem = realm.objects(Realmed.self) 获取它,因此它可能匹配也可能不匹配。您可以通过单步执行代码来测试它,看看应该如何返回行,然后如何检索该数据。
    • 是否可以看到您的代码。我的仍然崩溃,我确保所有计数都相同。谢谢
    • @NEWBY 了解您的代码在哪里崩溃可能会有所帮助。如果您可以创建一个最小的示例,您可能会考虑将其作为问题发布。如果您这样做,请务必详细说明您的故障排除步骤,并指出哪条线路崩溃以及错误是什么。
    • @NEWBY 您可能还想退后一步并查看您的代码...有一些事情需要清理或可能以不同的方式处理。例如,有一个类 var idValue,它是一个 int 数组,可在整个类中使用。然而,在你的代码中,相同的 var 被传递,这是不必要的,因为它是一个类 var,就像这个调用 deleteRealm(idInt: idValue)。这可能不是问题的根本原因,但可以在代码中更好地处理,并且清理可能会使代码更易于阅读和排除故障。
    【解决方案2】:

    这就是我设法解决这个问题的方法。

        import UIKit
    import Realm
    import RealmSwift
    
    class OtherViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        var notificationToken: NotificationToken? = nil
    
        @IBOutlet weak var otherTableView: UITableView!
    
        var realm: Realm!
        var realmedData = ""
    
        var realmList: Results<RealmTwo> {
            get {
                return realm.objects(RealmTwo.self).filter("%@ == realmLbl", realmedData)
            }
        }
        var realmingList: Results<RealmTwo> {
            get {
                return realm.objects(RealmTwo.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.allowsMultipleSelectionDuringEditing = true
            realm = try! Realm()
            notificationToken = realmList.observe { [weak self] (changes: RealmCollectionChange) in
                guard let tableView = self?.otherTableView else {return}
                switch changes {
                case .initial:
                    tableView.reloadData()
                case .update(_, let deletions, let insertions, let modifications):
                    tableView.beginUpdates()
                    tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }),
                                         with: .automatic)
    
                    tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}),
                                         with: .automatic)
                    tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }),
                                         with: .automatic)
                    tableView.endUpdates()
                case .error(let error):
                    fatalError("\(error)")
                }
            }
            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"
            } else if testingBool == false {
                deleteBtn.title = "Delete"
            }
        }
    
        func didPressRemove() {
            if testingBool == false {
                print("Select what to Delete")
            } else {
                deleteRealm(idInt: idValue)
                otherTableView.isEditing = false
            }
        }
    
        @IBAction func pressEdit(_ sender: Any) {
            testingBool = !testingBool
            if testingBool == true {
                otherTableView.isEditing = true
            } else if testingBool == false {
                otherTableView.isEditing = false
            }
        }
    
        @IBAction func pressDelete(_ sender: Any) {
            deleteRealm(idInt: idValue)
    
        }
    
        func deleteRealm(idInt: [Int]) {
            do {
                try realm.write {
                    for deleteIndex in idInt {
                        let deletingValue = realmList.filter("id == %@", deleteIndex as Any)
                        print("DeleteValue: \(deletingValue)")
                        realm.delete(deletingValue)
    
                    }
                }
            } catch {
    
            }
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return realmList.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
            cell.otherLbl.text = realmList.filter("%@ == realmLbl", realmedData)[indexPath.row].spanish
            return cell
        }
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            if otherTableView.isEditing == false {
            } else {
                let idArr = realmList.filter("%@ == realmLbl", realmedData)[indexPath.row].id
                self.idValue.append(idArr)
                print("ID: \(idValue)")
            }
        }
    
    
        func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
            if otherTableView.isEditing == true {
                let idArr = realmList.filter("%@ == realmLbl", realmedData)[indexPath.row].id
                if let index = idValue.index(of: idArr) {
                    idValue.remove(at: index)
                    print("ID: \(idValue)")
                }
            }
        }
        deinit {
            notificationToken?.invalidate()
        }
    }
    

    谢谢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-01
      • 1970-01-01
      • 2015-01-02
      • 2023-03-06
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多