Xcode Playground 使用简单的 UITableViewController 代码崩溃

Xcode Playground crashes with a simple UITableViewController code

我在 Xcode Playground 中遇到了一个关于 UITableViewController 子类实例的非常奇怪的问题。 我在 viewDidLoad 中以编程方式注册了两个 UITableViewCell,并在 cellForRowAt 方法中将单元格出队:

import UIKit
import PlaygroundSupport

class ViewController: UITableViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
  }

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

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    switch indexPath.row {
    case 0:
      return tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
    case 1:
      return tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
    default:
      fatalError()
    }
  }
}

let vc = ViewController(style: .plain)
PlaygroundPage.current.liveView = vc


但是 Playground 抛出 NSException 并显示:

error: Execution was interrupted, reason: signal SIGABRT.
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.

请注意,此代码在带有 iPhone 模拟器的合法 Xcode 项目中运行良好。是我弄错了还是bug?

我使用的是版本 10.3 (10G8)。

奇怪的错误...

这很好用:

class ViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
    }
}

但这会崩溃:

class ViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
    }
}

的区别是崩溃的例子返回了second注册单元格.

如果交换 .register() 语句的顺序,则 "cell2" 可以正常工作,而 "cell1" 会崩溃。


编辑 (编辑 2:我们需要分配 .delegate.dataSource——可以在 loadView()viewDidLoad())

请注意,由于仅注册(和使用)一个单元格按原样工作,因此不应该 设置视图。但是,如果您在 loadView() 中设置视图,代码将在 Playground 中 运行 而不会崩溃:

class ViewController: UITableViewController {

    override func loadView() {
        let v = UITableView()
        v.delegate = self
        v.dataSource = self
        self.view = v
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch indexPath.row {
        case 0:
            return tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
        case 1:
            return tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
        default:
            fatalError()
        }
    }
}