当numberOfRowsInSection大于1

时间:2017-01-29 06:35:26

标签: ios iphone swift uitableview

我似乎无法让我的自定义UITableView类作为另一个UITableView中存在的UITextField的inputView正常工作。

请参阅下面的屏幕截图。我有MainTableViewController,它包含两个部分:Section-1和Section-2。每个部分只包含一个单元格。每个单元格都有一个UITextField。第1节是关注的领域。它包含一个UITextField,其自定义UITableView作为其inputView。我命名了这个自定义的UITableView InputTableView并实现了UITableViewDataSource协议。

class InputTableView: UITableView, UITableViewDataSource

目标是让InputTableView像选项选择器一样。用户将单击InputTableView中的单元格,该选择将填充specialTextField

单击单元格时,InputView按预期显示。 Test Title是UITableView部分标题。 Section 0 Row 0是单元格内容。

UITableViewController Image

这是InputTableView类中的numberOfRowsInSection

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  print("tableView numberOfRowsInSection")
  return 1
}

如果我返回大于1的任何内容,应用程序将崩溃并出现如下错误:

  

TableViewControllerTest [721:126633] *由于终止应用程序   未捕获的异常'NSRangeException',原因:'*    - [__ NSSingleObjectArrayI objectAtIndex:]:索引1超出边界[0 .. 0]'   ***首先抛出调用堆栈:(0x18db211b8 0x18c55855c 0x18db12420 0x19417c7bc 0x193ee7a40 0x193d1f9d4 0x193af5c20 0x193ab5478   0x193ab48c8 0x193ab4654 0x193ab4488 0x193d12e74 0x193d125a4   0x193d124a0 0x193a54550 0x193d35120 0x193d34aac 0x193a5399c   0x193a52fcc 0x1939d3090 0x1939f6c58 0x1939d22c4 0x18e57ad10   0x1939d2138 0x1939de018 0x1939dd904 0x1943b2298 0x1943b37f8   0x1943ac3c8 0x1943b37c8 0x1943a8488 0x1943b331c 0x1943abe38   0x193a9d240 0x1a1d15e98 0x1939fca78 0x193a5ab4c 0x193a5aebc   0x193add0b4 0x193b84128 0x193b83630 0x193f9ef80 0x193fa2688   0x193b6973c 0x193a080f0 0x193f92680 0x193f921e0 0x193f9149c   0x193a0630c 0x1939d6da0 0x1a1cb21e8 0x1941c075c 0x1941ba130   0x18daceb5c 0x18dace4a4 0x18dacc0a4 0x18d9fa2b8 0x18f4ae198   0x193a417fc 0x193a3c534 0x1000191f4 0x18c9dd5b8)libc ++ abi.dylib:   以NSException(lldb)

类型的未捕获异常终止

1)如果我向MainTableViewController添加另一行(将1行添加到Section-1总共2行),则numberOfRowsInSection可以返回2并运行正常。如果我添加另一行总共3行,那么该函数可以返回3并运行正常。任何更大的东西,它再次崩溃。我认为这些是有点相关的。但是,如果这两个项目甚至不属于同一个类,怎么可能呢?

2)如果我注释掉行inputTableView.delegate = self,那么代码会再次运行而不会崩溃。我可以设置numberOfRowsInSection来返回任何数字(我试过5并且它有效)。但是,因为现在没有设置委托,所以我无法对用户交互做任何事情。

我的完整代码:

//
//  MainTableViewController.swift
//  TableViewControllerTest
//
//  Created by Zion Perez on 1/29/17.
//  Copyright © 2017 Zion Perez. All rights reserved.
//

import UIKit

class InputTableView: UITableView, UITableViewDataSource {

    func setupTableView(){
        self.dataSource = self
    }

    // MARK: - TableView DataSource
    // https://developer.apple.com/reference/uikit/uitableviewdatasource
    func numberOfSections(in tableView: UITableView) -> Int {
        print("numberOfSections")
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("tableView numberOfRowsInSection")
        return 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("tableView cellForRowAt: " + indexPath.description)

        let id = "BasicCell"
        var cell: UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: id)
        if cell == nil {
            cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: id)
        }
        cell?.textLabel?.text = "Section \(indexPath.section) Row \(indexPath.row)"
        return cell!
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        print("tableView titleForHeaderInSection")
        return "Test Title"
    }
}

class MainTableViewController: UITableViewController {

    @IBOutlet weak var specialTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let frame = CGRect(x: self.view.frame.minX, y: self.view.frame.minY, width: self.view.frame.width, height: 200.0)
        let inputTableView = InputTableView(frame: frame)
        inputTableView.setupTableView()
        inputTableView.delegate = self
        specialTextField.inputView = inputTableView
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - TableViewDelegate
    // https://developer.apple.com/reference/uikit/uitableviewdelegate
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("selected row at " + indexPath.description)
    }

    override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        print("deselected row at " + indexPath.description)
    }
}

我的代码也在Github上: https://github.com/starkindustries/TableViewControllerTest

我研究过的其他资料来源: UITableView crashes when number of rows >1

编辑(已解决的注释):

Muescha的回答帮助我解决了我的问题。作为参考,可以在下面的github链接(delegateRefactor分支)中找到代码的固定版本。带有问题的原始代码位于上面的github链接(主分支)。

https://github.com/starkindustries/TableViewControllerTest/tree/delegateRefactor

3 个答案:

答案 0 :(得分:1)

您还需要在UITableViewDelegate上添加InputTableView

为什么呢?因为您之前在ViewController中已经拥有它(您应该将其命名为TableViewControllerMainTableViewController,以便其他人有一个不是普通视图控制器的提示。)

但您已在Interface Builder中绘制了2个部分,每个部分有1个单元格。此单元格由隐藏的UITableViewDataSource和隐藏的UITableViewDelegate填充。如果我在表视图中单击并在界面生成器中查看传出连接但在那里没有类文件。

我认为当UITableViewDelegate的{​​{1}}设置为InputTableView时,它们会在其他请求中崩溃。在崩溃堆栈跟踪中,还有一个MainTableViewController调用最后一次调用之一(这就是为什么:比你发布的更多错误和堆栈跟踪问题:最好找出错误 - 非常好你发布你的示例项目到github。否则主要故事板中的单元格设置将被隐藏给审阅者)

但是第一部分的主表上只有一个单元格。这就是为什么它与2个细胞坠毁。它试图获得单元格2的高度,但只有0 ... 0索引,这意味着= 1个单元格。

难点在于,heightForRowAt的{​​{1}}和UITableViewDataSource隐藏在某个地方并自动启动了一些方法。 (这就是为什么我个人不喜欢界面构建器和故事板,并通过代码完成所有操作)

这里的证明截图:

enter image description here

代码更改:

  • UITableViewDelegate已移至MainTableViewController

  • 协议self.delegate = self已添加到InputTableView

这是代码:

UITableViewDelegate

答案 1 :(得分:0)

也许问题是因为UITableViewController子类... 它只需要一个表视图。只需将输入视图的委托分配给它自己,然后使用自定义委托将选定的索引或所需信息发送回表视图控制器。

答案 2 :(得分:0)

我认为你应该直接在ViewController中处理InputTableView的那些dataSource方法。

import UIKit

class InputTableView: UITableView, UITableViewDataSource {

    func setupTableView(){
        self.dataSource = self
    }

    // MARK: - TableView DataSource
    // https://developer.apple.com/reference/uikit/uitableviewdatasource  
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("tableView cellForRowAt: " + indexPath.description)

        let id = "BasicCell"
        var cell: UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: id)
        if cell == nil {
            cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: id)
        }
        cell?.textLabel?.text = "Section \(indexPath.section) Row \(indexPath.row)"
        return cell!
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        print("tableView titleForHeaderInSection")
        return "Test Title"
    }
}

class ViewController: UITableViewController {

    @IBOutlet weak var specialTextField: UITextField!
    var inputTableView: InputTableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let frame = CGRect(x: self.view.frame.minX, y: self.view.frame.minY, width: self.view.frame.width, height: 200.0)
        inputTableView = InputTableView(frame: frame)
        inputTableView.setupTableView()
        inputTableView.delegate = self
        specialTextField.inputView = inputTableView
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - TableViewDelegate
    // https://developer.apple.com/reference/uikit/uitableviewdelegate
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("selected row at " + indexPath.description)
    }

    override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        print("deselected row at " + indexPath.description)
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        if tableView == inputTableView {
           print("numberOfSections")
           return 1
        } else {
           deal with your other tableView
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == inputTableView {
           print("numberOfRowsInSection ")
           return 1
        } else {
           deal with your other tableView
        }
    }
}