ios - swift 3 : Error in TableView when deleting cells holding UserDefault values

标签 ios swift tableview userdefaults

我遵循了此处提供的所有步骤:The proper way to delete rows from UITableView and update array from NSUserDefaults in Swift / iOS

但是,会导致错误,说;

'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

我创造了

类 TableViewController: UITableViewController {

struct Section {
    var sectionName: String!
    var words: [String]!

    init(title: String, word: [String]) {
        self.sectionName = title
        self.words = word

    }
}

var arrayForRows = [String]()

var sections = [Section]()
func getData() -> [String] {
if let data = userDefaultDataSave.stringArray(forKey: "data") {
    return data
}
return []
}
override func viewDidLoad() {
    super.viewDidLoad()

    tableView.dataSource = self

    guard let data = dataDefaults.stringArray(forKey: "data") else {
        return
    }
    arrayForRows = data as [String]
    tableView.reloadData()

    sections = [
        Section(title: "A", word: []), // 1
        Section(title: "B", word: []), //2
        Section(title: "C", word: []),
        Section(title: "D", word: []),
        Section(title: "E", word: []),
        Section(title: "F", word: []),
        Section(title: "G", word: []),
        Section(title: "H", word: []),
        Section(title: "I", word: []),
        Section(title: "J", word: []),
        Section(title: "K", word: []),
        Section(title: "L", word: []),
        Section(title: "M", word: []),
        Section(title: "N", word: []),
        Section(title: "O", word: []),
        Section(title: "P", word: []),
        Section(title: "Q", word: []),
        Section(title: "R", word: []),
        Section(title: "S", word: []),
        Section(title: "T", word: []),
        Section(title: "U", word: []),
        Section(title: "V", word: []),
        Section(title: "W", word: []),
        Section(title: "X", word: []),
        Section(title: "Y", word: []),
        Section(title: "Z", word: [])
    ]


    let getAlphabetData = getData()

    for a in getAlphabetData {

        if a.hasPrefix("A") || a.hasPrefix("a") {
            if sections[0].sectionName == "A" {
                sections[0].words.append(a as String)
            }
        }

        if a.hasPrefix("B") || a.hasPrefix("b") {
            if sections[1].sectionName == "B" {
                sections[1].words.append(a as String)
            }
        }

        if a.hasPrefix("c") || a.hasPrefix("c") {
            if sections[2].sectionName == "C" {
                sections[2].words.append(a as String)
            }
        }
        if a.hasPrefix("D") || a.hasPrefix("d") {
            if sections[3].sectionName == "D" {
                sections[3].words.append(a as String)
            }
        }
        if a.hasPrefix("E") || a.hasPrefix("e") {
            if sections[4].sectionName == "E" {
                sections[4].words.append(a as String)
            }
        }
        if a.hasPrefix("F") || a.hasPrefix("f") {
            if sections[5].sectionName == "F" {
                sections[5].words.append(a as String)
            }
        }
        if a.hasPrefix("G") || a.hasPrefix("g") {
            if sections[6].sectionName == "G" {
                sections[6].words.append(a as String)
            }
        }
        if a.hasPrefix("H") || a.hasPrefix("h") {
            if sections[7].sectionName == "H" {
                sections[7].words.append(a as String)
            }
        }
        if a.hasPrefix("I") || a.hasPrefix("i") {
            if sections[8].sectionName == "I" {
                sections[8].words.append(a as String)
            }
        }
        if a.hasPrefix("J") || a.hasPrefix("j") {
            if sections[9].sectionName == "J" {
                sections[9].words.append(a as String)
            }
        }
        if a.hasPrefix("K") || a.hasPrefix("k") {
            if sections[10].sectionName == "K" {
                sections[10].words.append(a as String)
            }
        }
        if a.hasPrefix("L") || a.hasPrefix("l") {
            if sections[11].sectionName == "L" {
                sections[11].words.append(a as String)
            }
        }
        if a.hasPrefix("M") || a.hasPrefix("m") {
            if sections[12].sectionName == "M" {
                sections[12].words.append(a as String)
            }
        }
        if a.hasPrefix("N") || a.hasPrefix("n") {
            if sections[13].sectionName == "N" {
                sections[13].words.append(a as String)
            }
        }
        if a.hasPrefix("O") || a.hasPrefix("o") {
            if sections[14].sectionName == "O" {
                sections[14].words.append(a as String)
            }
        }
        if a.hasPrefix("P") || a.hasPrefix("p") {
            if sections[15].sectionName == "P" {
                sections[15].words.append(a as String)
            }
        }
        if a.hasPrefix("Q") || a.hasPrefix("q") {
            if sections[16].sectionName == "Q" {
                sections[16].words.append(a as String)
            }
        }
        if a.hasPrefix("R") || a.hasPrefix("r") {
            if sections[17].sectionName == "R" {
                sections[17].words.append(a as String)
            }
        }
        if a.hasPrefix("S") || a.hasPrefix("s") {
            if sections[18].sectionName == "S" {
                sections[18].words.append(a as String)
            }
        }
        if a.hasPrefix("T") || a.hasPrefix("t") {
            if sections[19].sectionName == "T" {
                sections[19].words.append(a as String)
            }
        }
        if a.hasPrefix("U") || a.hasPrefix("u") {
            if sections[20].sectionName == "U" {
                sections[20].words.append(a as String)
            }
        }
        if a.hasPrefix("V") || a.hasPrefix("v") {
            if sections[21].sectionName == "V" {
                sections[21].words.append(a as String)
            }
        }
        if a.hasPrefix("W") || a.hasPrefix("w") {
            if sections[22].sectionName == "W" {
                sections[22].words.append(a as String)
            }
        }
        if a.hasPrefix("X") || a.hasPrefix("x") {
            if sections[23].sectionName == "X" {
                sections[23].words.append(a as String)
            }
        }
        if a.hasPrefix("Y") || a.hasPrefix("y") {
            if sections[24].sectionName == "Y" {
                sections[24].words.append(a as String)
            }
        }
        if a.hasPrefix("Z") || a.hasPrefix("z") {
            if sections[25].sectionName == "Z" {
                sections[25].words.append(a as String)
            }
        }
    }

}

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return sections.count
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 50.0
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows

    return arrayForRows.count
}


override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sections[section].sectionName
}



override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

    // Cellに値を設定する.
    cell.textLabel?.font = UIFont.systemFont(ofSize: 20)
    cell.textLabel?.textColor = UIColor.black

    cell.textLabel!.text = sections[indexPath.section].words[indexPath.row]

    return cell
}

// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    if editingStyle == .delete {
        // Delete the row from the data source

        tableView.beginUpdates()

        arrayForRows.remove(at: indexPath.row)
        self.tableView.deleteRows(at: [indexPath], with: .automatic)

        let userDefaults = UserDefaults.standard
        userDefaults.set(arrayForRows, forKey: "data")
        tableView.endUpdates()
    } else if editingStyle == .insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }

}

从另一个Controller,通过这种方式将值添加到Section的words数组中;

  class InputDataViewController: UIViewController {


 // this function is written inside UITextView in this class. 
 //But I omitted here. 

 func addData(text: String) {

    var data = self.getData()
    data.insert(text as NSString, at: 0)
    dataDefault.set(data, forKey: "data")
}


func getData() -> [String] {
    if let data = dataDefault.stringArray(forKey: "data") {
        return data
    }
    return []
 }

}

问题是什么?从我的角度来看,我可以理解如果我没有显式地写tableView.reloadData()tableView.beginUpdates()endUpdates(),但我做到了。导致这个错误的原因是什么?你可以帮帮我吗?

谢谢。

已更新

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return sections[section].words.count
}

另外,我发现如果我这样写,它会奏效。但是,所选的一个并没有从我的表格 View 中删除。无论我选择并删除了一个部分中的一行,单词的第一个索引都从我的 TableView 中删除了。删除的行在另一个部分。

  override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    if editingStyle == .delete {
        // Delete the row from the data source
        //            removeHistory(index: sections[indexPath.section].words[indexPath.row])

        tableView.beginUpdates()

        let indexSet = NSMutableIndexSet()
        indexSet.add(indexPath.section)


        //let indexSet = sections[indexPath.section].words[indexPath.row] as IndexSet
        //sections.remove(at: indexPath.section)
        sections[indexPath.section].words.remove(at: indexPath.row)
        var data = getData()
        data.remove(at: indexPath.row)
        dataDefault.set(data, forKey: "data")
        dataDefault.synchronize()

        //tableView.deleteSections(indexSet, with: UITableViewRowAnimation.fade)
        tableView.deleteRows(at: [indexPath], with: .fade)

        tableView.endUpdates()
        //



    } else if editingStyle == .insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }
}

最佳答案

您必须确保每次添加或删除行时都保持数据源一致。在您的情况下,您要从 arrayForRows 中删除对象,但您的 numberOfRows 使用的是完全不同的数据源:sections[section].words.count

所以你应该要么

  1. 保持 numberOfRows 不变,并从 sections[indexPath.section].words 数组中删除
  2. 更改您的 nubmerOfRows 方法以返回 arrayForRows.count

只需选择您的数据源并选择正确的选项即可。由于您有多个部分,因此您应该遵循第一个建议。

编辑:

您收到 index out of bounds 错误,因为您似乎从未更新过 sections 数组。您应该为每个部分填充所有这些 words 数组,对吗?但是根据您提供的代码判断它们总是空的。

基本上你的实现应该是这样的:

  1. ViewController A 显示一个部分列表,每个部分中的单词都以特定字母开头
  2. ViewController B 创建新元素并将它们保存到 UserDefaults。
  3. VC A 应该每次在viewWillAppear 方法中更新sections 数组。只需循环遍历 UserDefaults 数组中的所有元素,并将每个元素放入正确的 Section 对象中。
  4. 每次在 VC A 中删除一行时,您必须将其从相应的 Section 对象中删除,否则应用程序将崩溃。此外,您应该从 UserDefaults 数组中删除相同的对象,以保持这些更改的持久性。

将单词插入 sections 数组的函数示例:

func insert(word: String) {
    guard word.characters.count > 0 else { return }
    let firstLetter = String(describing: word.characters.first).lowercased()
    for var section in sections {
        if section.title.lowercased().hasPrefix(firstLetter) {
            section.words.append(word)
        }
    }
}

关于ios - swift 3 : Error in TableView when deleting cells holding UserDefault values,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40332030/

相关文章:

ios - 滚动时隐藏tableViewCell中的复选标记

iphone - UIView 意外进入状态栏下方

ios - 根据键值查询PFUser(Swift)

ios - 是否有可能创建对结构数组元素的引用?

JavaFX : How to populate data to TableView from different Thread(Netty)

ios - Swift:无法在没有参数的情况下调用 'reloadData'

ios - GAD adLoader 委托(delegate)未被调用

ios - 手动设置日期以使日期选择器始终返回一个日期

arrays - Swift - 使用范围运算符将项目添加到数组,奇怪的行为

ios - 如何动态扩展 tableview 中的单元格?