0

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

但是,会导致错误,说;

'无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (2) 必须等于更新前该节中包含的行数 (2),加上或减去从该部分插入或删除的行数(0 插入,1 删除)加上或减去移入或移出该部分的行数(0 移入,0 移出)。

我创造了

类 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
    }

}

}

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

  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()ortableView.beginUpdates()和,我可以理解endUpdates(),但我确实做到了。导致此错误的原因是什么?你可以帮帮我吗?

谢谢。

更新

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

另外,我发现如果我这样写,它会起作用。但是,选定的一个没有从我的表格视图中删除。单词的第一个索引已从我的表格视图中删除,无论我选择并删除了一个部分中的一行。删除的行在另一个部分中。

  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
    }
}
4

2 回答 2

1

您必须确保每次添加或删除行时,您的数据源都保持一致。在您的情况下,您正在删除对象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 应该sections每次在viewWillAppear方法中更新数组。只需从 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)
        }
    }
}
于 2016-10-30T18:50:22.420 回答
0

也许问题是您在删除数据之前从表视图中删除了行?尝试从数组中删除对象,然后从 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()

还尝试查看您的 numberOfRowsInSection 方法。我想它应该返回

arrayForRows.count
于 2016-10-30T18:36:53.120 回答