[英]Swift3: Error in TableView when deleting cells holding UserDefault values
I followed all steps provided here: The proper way to delete rows from UITableView and update array from NSUserDefaults in Swift / iOS 我遵循了此处提供的所有步骤: 在Swift / iOS中从UITableView删除行并从NSUserDefaults更新数组的正确方法
However, an error is caused, saying; 但是,会导致错误。
'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).' '无效的更新:第0节中无效的行数。更新(2)之后,现有节中包含的行数必须等于更新(2)之前该节中包含的行数,加上或减去从该部分插入或删除的行数(插入0,已删除1),加上或减去移入或移出该部分的行数(移入0,移出0)。
I have created 我创造了
class TableViewController: UITableViewController { 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
}
}
} }
From another Controller, values are added into the Section's words
array, by writing this way; 通过另一种编写方式,可以从另一个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 []
}
}
What is the problem? 问题是什么? From the way I see it, I can understand if I did not explicitly write tableView.reloadData()
or tableView.beginUpdates()
and endUpdates()
, but I did. 从我的观察角度,我可以理解是否没有显式编写tableView.reloadData()
或tableView.beginUpdates()
和endUpdates()
,但是我做到了。 What is the reason for causing this error? 导致此错误的原因是什么? Could you help me? 你可以帮帮我吗?
Thanks. 谢谢。
Updated 更新
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return sections[section].words.count
}
Also, I found out that if I write this way, it worked. 另外,我发现如果我用这种方式编写,它会起作用。 However, the selected one was not deleted from my table view. 但是,所选的那个并没有从我的表格视图中删除。 The first index of word was deleted from my table view regardless of the fact that I chose and deleted a row in a section. 无论我选择并删除某节中的一行,都是从表视图中删除单词的第一个索引。 The deleted row was in another section. 删除的行在另一部分中。
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
}
}
You must make sure that every time you add or delete rows, you keep your data source consistant. 您必须确保每次添加或删除行时,都必须使数据源保持一致。 In your case you're removing object fron arrayForRows
but your numberOfRows
is using a completely different data source: sections[section].words.count
在您的情况下,您将删除arrayForRows
对象,但numberOfRows
使用的是完全不同的数据源: sections[section].words.count
So you should either 所以你应该
numberOfRows
as it is and remove from sections[indexPath.section].words
array 保持numberOfRows
sections[indexPath.section].words
并从sections[indexPath.section].words
数组中删除 nubmerOfRows
method to return arrayForRows.count
更改您的nubmerOfRows
方法以返回arrayForRows.count
Just make your choice what is your dataSource and pick the right option. 只需选择什么是数据源,然后选择正确的选项即可。 Since you have multiple sections, you should follow the first suggestion. 由于您有多个部分,因此应遵循第一个建议。
Edit: 编辑:
You're getting index out of bounds
error because it seems you never update your sections
array. 您正在获取index out of bounds
错误,因为似乎您从未更新过sections
数组。 You should fill all those words
arrays for every section, right? 您应该为每个部分填充所有这些words
数组,对吗? But judging by the code you provided they are always empty. 但是从您提供的代码来看,它们始终为空。
Basically your implementation should look like this: 基本上,您的实现应如下所示:
sections
array every time in viewWillAppear
method. VC A应该每次在viewWillAppear
方法中更新sections
数组。 Just make a loop through all elements in the array from UserDefaults and put every element into the right Section
object. 只需从UserDefaults中遍历数组中的所有元素,然后将每个元素放入正确的Section
对象即可。 Example for a function to insert a word into your sections
array: 将单词插入您的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)
}
}
}
Maybe the problem is that you delete row from table view before deleting data? 也许问题是您在删除数据之前从表视图中删除了行? try to delete object from your array and only then delete row from tableView 尝试从数组中删除对象,然后再从tableView中删除行
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()
Also try to look at your numberOfRowsInSection method. 还尝试查看您的numberOfRowsInSection方法。 I guess it should return 我想它应该回来
arrayForRows.count
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.