Swift 中的自定义 UITableViewCell 注册类

Posted

技术标签:

【中文标题】Swift 中的自定义 UITableViewCell 注册类【英文标题】:Custom UITableViewCell register class in Swift 【发布时间】:2014-07-15 06:42:44 【问题描述】:

在我的应用程序中,我根据数组填充表格。该表使用自定义 UITableViewCell。一切正常,桌子满了。然后我将搜索显示控制器添加到我的 UITableViewController 中,无需编写代码来处理搜索,只需添加控制器即可。当您运行应用程序时,表格仍然被填满。但是如果我尝试单击搜索栏,则会收到错误消息:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier CitiesListCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

我尝试在 UITableViewController 行中添加我的 viewDidLoad 函数:

self.tableView.registerClass(MyCell.classForCoder(), forCellReuseIdentifier: kCellIdentifier)

启动应用程序并立即得到错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

在线cell.cellMyCity.text = cellText

我做错了什么?

这是我的自定义 UITableViewCell 类:

import UIKit

class MyCell: UITableViewCell 

@IBOutlet var cellMyImage: UIImageView
@IBOutlet var cellMyCity: UILabel
@IBOutlet var cellMyCountry: UILabel
@IBOutlet var cellMyTemp: UILabel

init(style: UITableViewCellStyle, reuseIdentifier: String!) 
    super.init(style: style, reuseIdentifier: reuseIdentifier)


override func awakeFromNib() 
    super.awakeFromNib()


override func setSelected(selected: Bool, animated: Bool) 
    super.setSelected(selected, animated: animated)



这是单元格的代码:

override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! 

    var cell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier, forIndexPath: indexPath) as MyCell!

    if cell == nil 
        cell = MyCell(style: UITableViewCellStyle.Default, reuseIdentifier: kCellIdentifier)
    

    let cellText: String? = dataWeatherSelectedCity[indexPath.row].name as  String
    println("Строка: \(cellText)")
    cell.cellMyCity.text = cellText

    let cellSubtitle: String? = dataWeatherSelectedCity[indexPath.row].country as String
    cell.cellMyCountry.text = cellSubtitle

    cell.cellMyImage.image = UIImage(named: "Blank52")

    var currentCityWeatherURL = "http://api.wunderground.com/api/\(self.myAPI.kWundergroundApiKey)/conditions/lang:RU/q/zmw:\(self.dataWeatherSelectedCity[indexPath.row].zmv).json"

    var fullObservation:NSDictionary = self.myAPI.jsonParsingWeather(currentCityWeatherURL)
    var currentObservation:NSDictionary = fullObservation.valueForKey("current_observation") as NSDictionary

    var currentWeather = self.myAPI.parsingOneCityCurrentCondition(currentObservation)       
    cell.cellMyImage.image = currentWeather.image
    cell.cellMyTemp.text = currentWeather.temp
    return cell

TableViewCell 中的属性:

没有self.tableView.registerClass(MyCell.classForCoder(), forCellReuseIdentifier: kCellIdentifier)self.tableView.registerClass(MyCell.self, forCellReuseIdentifier: kCellIdentifier) 的表:

【问题讨论】:

我没有在您的帖子中看到您在 IB 中为您的单元格设置了 reuse identifier... 更新的图片在哪里?我没有看到任何... 现在你看到我编辑过的帖子中的图片了吗? 你试过object_getClass(MyCell)而不是MyCell.classForCoder()MyCell.self吗?这在 Swift... 中对我来说在逻辑上看起来更正确 刚试过-Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'must pass a class of kind UITableViewCell' 【参考方案1】:

我所做的工作是这样的:

class MainViewController: UIViewController 

    // ...

    @IBOutlet var tableView: UITableView

    override func viewDidLoad() 
        super.viewDidLoad()

        self.tableView.registerNib(UINib(nibName: "UICustomTableViewCell", bundle: nil), forCellReuseIdentifier: "UICustomTableViewCell")

        // ...
    

    // ...


注意:如果我使用 –registerClass(_: forCellReuseIdentifier:) 方法,将不会加载 xib 文件,因此除非您以编程方式将内容添加到单元格,否则不会出现实际的自定义界面.如果你想从一个 nib 文件加载界面,你需要用它的 nib 注册单元格。


遵守基本协议:

extension MainViewController: UITableViewDataSource 
    
    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int 
        return 3
    
    
    func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! 
        let cell: UICustomTableViewCell = tableView.dequeueReusableCellWithIdentifier(UICustomTableViewCell.reuseIdentifier) as UICustomTableViewCell
        println(cell)
        return cell;
    
    


//

extension MainViewController: UITableViewDelegate 
    
    func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat 
        return 44.0
    
    


并且自定义单元类是一个非常通用的类,其名称为UICustomTableViewCell

class UICustomTableViewCell: UITableViewCell 

    class var reuseIdentifier: String 
        get 
            return "UICustomTableViewCell"
        
    
    
    override func awakeFromNib() 
        super.awakeFromNib()
        // Initialization code
    

    override func setSelected(selected: Bool, animated: Bool) 
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    
    


具有相当随机的界面:

以及自定义类重用标识符的这些设置:


我屏幕上的最终结果与我预期的一样,只有 3 行:

注意:要进一步自定义自定义单元格,您可能需要扩展上面的代码。

更新

使用UISearchBar,最终结果会是这样的:

【讨论】:

我的意思是,我肯定需要为单元格制作 xib?没有它就不行吗? 不,您不需要为自定义单元格制作 xib,如果您更喜欢这种方式,您可以通过编程方式创建整个自定义内容。 您能建议我如何在我的项目中实现它吗? 恐怕我不明白您的问题...您可以将自定义视图/图层添加到您的自定义单元格中,例如–init(style:reuseIdentifier:) 或者通常您可以使用–willMoveToSuperview(newSuperview:) 甚至–didMoveToSuperview() 方法来自定义视图。 好的。尝试使用带有搜索显示控制器的标准表格【参考方案2】:

tableView 之前添加self 可以解决问题:

var cell = self.tableView.dequeueReusableCellWithIdentifier(kCellIdentifier, forIndexPath: indexPath) as MyCell!

【讨论】:

简单有效。为我工作。 这是对我有用的解决方案(XCode 7.2 & Swift v2) wtf... 谁能解释一下为什么会这样? self 对我来说似乎很随意。【参考方案3】:

由于错误提示您正在获取您的 cellUITestField nilSwift 不支持对 nil 对象进行方法调用,这就是您崩溃的原因。您可以通过检查对象是否为 nil 来防止崩溃,如下所示

if var label = cell.cellMyCity
    label.text = cellText

编辑

我想我知道这里有什么问题......

您在storyboard 中有拖放UISearchBar,因此默认情况下,所有数据源和委托 都设置为您的控制器,例如ViewController(您覆盖UITableView 的类DataSource 方法)并在 ViewController 中将 MyCell 类注册为您的自定义类。 因此,您的 tableView 显示完美,但是当您向 UISearchBar 键入内容时,同样的 DataSource 方法 (ViewController) 也会被调用,并且您会为 searchResultsTableView 注册 MyCell(UISearchDisplayController tableView 即显示搜索结果),但事实并非如此了解 MyCell ,这就是为什么 cell.cellMyCity 在搜索时为零的原因,这意味着 searchResultsTableView 期望默认的 UITableViewCell 并且您没有为默认单元格设置任何内容 -

cell.textLabel.text = countryList[indexPath.row]

您可以通过如下更改 DataSource 方法来观察整个场景

    override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! 

    var cell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as MyCell!
    if cell == nil 
        //tableView.registerNib(UINib(nibName: "UICustomTableViewCell", bundle: nil), forCellReuseIdentifier: "UICustomTableViewCell")
        tableView.registerClass(MyCell.classForCoder(), forCellReuseIdentifier: kCellIdentifier)

        cell = MyCell(style: UITableViewCellStyle.Default, reuseIdentifier: kCellIdentifier)
    
    if var label = cell.cellMyCity
        label.text = countryList[indexPath.row]
    
    else
        cell.textLabel.text = countryList[indexPath.row]
    
    return cell

解决方案而言,可能有两种可能的解决方案..

A)。不要使用searchResultsTableView(由UISearchDisplayController 提供)并在ViewController 中的tableView 中显示您的搜索结果。为此,您可以做的是 - 当用户在 UISearchBar 中键入某些内容时,收听 UISearchBar 代表通过谓词获取您的结果数据源(可能在不同的数组中)并在相同的 UITableView 中显示结果。

B)。自定义 UISearchDisplayController 并在 searchResultsTableView 中使用您的自定义单元格(即 MyCell)

【讨论】:

你每次都得到单元格对象 nil 吗?? 如果我使用self.tableView.registerClass(MyCell.self, forCellReuseIdentifier: kCellIdentifier) - 那么每次。如果我不使用它,那么一切都很好 - 表已填满。但粉碎搜索显示控制器 感谢有用的回答! 我还是不明白这个问题!但这解决了它【参考方案4】:

如果您使用故事板,请确保删除注册类,因为它会覆盖故事板以及与之关联的所有外链

请检查 https://***.com/a/26350795/4453583

它对我有用 =)

【讨论】:

【参考方案5】:

您必须记住为任何使用它的 tableView 注册单元格 - 包括 searchDisplayController.tableView。

【讨论】:

以上是关于Swift 中的自定义 UITableViewCell 注册类的主要内容,如果未能解决你的问题,请参考以下文章

swift Swift 4中的自定义JSON编码/解码

swift swift中的自定义随机数运算符

Swift 中的自定义输入视图

Swift 中的自定义 MKAnnotation 未添加到地图的注释中

swift swift中的自定义整数运算符,允许您连接整数

Swift 中的自定义地图