关于 ios:tableView.insertRows 抛出 NSException,但在 `[[0,0]]` 处的 `insertRows` 时不会

tableView.insertRows throws NSException, but not when `insertRows` at `[[0,0]]`

我正在关注本教程的修改(简化)版本,非常类似于此处的内容:

https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ImplementNavigation.html#//apple_ref/doc/uid/TP40015214-CH16-SW1

这是我的 UITableViewController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import UIKit

class NewsTableViewController: UITableViewController {

    @IBOutlet var newsTableView: UITableView!

    /*
        MARK: properties
    */
    var news = NewsData()

    override func viewDidLoad() {
        super.viewDidLoad()
        dummyNewData()
    }

    // MARK: - Table view data source
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return news.length()
    }


    // here we communicate with parts of the app that owns the data
    override func tableView(_ tableView: UITableView
                           , cellForRowAt indexPath: IndexPath
                           ) -> UITableViewCell {

        // note here we're using the native cell class
        let cell = tableView.dequeueReusableCell(withIdentifier:"newsCell", for: indexPath)
        // Configure the cell...
        let row : Int = indexPath.row
        cell.textLabel?.text = news.read(idx: row)
        return cell
    }


    // MARK: Navigation ****************************************************************

    // accept message from CreateNewViewController
    @IBAction func unwindToCreateNewView(sender: UIStoryboardSegue){

        if let srcViewController = sender.source as? CreateNewsViewController
        , let msg = srcViewController.message {

            // push into news instance and display on table
            news.write(msg: msg)
            let idxPath = IndexPath(row: news.length(), section: 1)

            // tableView.insertRows(at: [idxPath], with: .automatic)
            tableView.insertRows(at: [[0,0]], with: .automatic)

            print("unwound with message:", msg, idxPath)
            print("news now has n pieces of news:", news.length())
            print("the last news is:", news.peek())

        }

    }


    /*
        @DEBUG: debugging functions that display things on screen **************************
    */
    // push some values into new data
    private func dummyNewData(){

        print("dummyNewData")
        news.write(msg:"hello world first message")
        news.write(msg:"hello world second message")
        news.write(msg:"hello world third message")
    }

}

问题出在函数 unwindToCreateNewView:

1
2
let idxPath = IndexPath(row: news.length(), section: 1)
tableView.insertRows(at: [idxPath], with: .automatic)

其中 news.length() 给了我一个 Int 基本上是 someArray.count.

当我 insertRows(at: [idxPath] ...) 时,我得到错误:

1
libc++abi.dylib: terminating with uncaught exception of type NSException

但是当我只是硬编码它时:

1
tableView.insertRows(at: [[0,0]], with: .automatic)

它工作得很好。在模拟器上,我看到新消息插入到以前的消息下方。什么给了?


下面的代码有一个"off by one"问题:

1
2
news.write(msg: msg)
let idxPath = IndexPath(row: news.length(), section: 1)

假设在调用这段代码之前,news 中没有任何项目。这意味着有 0 行。当您想添加新行时,您需要在第 0 行插入,因为行号从 0 开始。

调用 news.write(msg: msg) 添加新项目,其长度现在为 1.

调用 IndexPath(row: news.length(), section: 1) 将行设置为 1 但它必须为 0。

一个简单的解决方案是交换这两行:

1
2
let idxPath = IndexPath(row: news.length(), section: 1)
news.write(msg: msg)

这将创建具有正确行号的索引路径。

而且由于这是第一个(也是唯一一个)节,除了上述更改之外,节号还需要更改为 0。

1
2
let idxPath = IndexPath(row: news.length(), section: 0)
news.write(msg: msg)