Alexey Nakhimov Alexey Nakhimov - 5 months ago 40
Swift Question

Custom UITableViewCell register class in Swift

In my application, I fill the table on the basis of the array. The table uses custom UITableViewCell. Everything works fine, table is filled. Then I add Search Display Controller to my UITableViewController, no write code to handle the search, simply add the controller. When you run the application, the table is still filled.But if I try to click on the search bar, I get the error:

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'


I try to add to my viewDidLoad function in UITableViewController line:

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


Launch the application and immediately get the error:

fatal error: unexpectedly found nil while unwrapping an Optional value


In line
cell.cellMyCity.text = cellText


What am I doing wrong?

This is my Custom UITableViewCell class:

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)

}
}


This is code for cell:

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
}


Property in TableViewCell:
enter image description here
enter image description here
enter image description here

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

enter image description here

Answer

As error suggest you are getting your cell or UITestField nil and Swift doesn't support method call on nil object that's why you are getting crash. you can prevent crash by checking the object is nil or not as bellow

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

EDIT

I think I got what is the problem here...

You have drag-n-drop UISearchBar in your storyboard, So by defaults all data source and delegate set to your Controller say, ViewController(class in which you override UITableView DataSource methods) and in that ViewController you register MyCell class as your customize class. So your tableView displays perfect but when you type something to UISearchBar, same DataSource methods (ViewController) called and there as well, you registers MyCell for searchResultsTableView (UISearchDisplayController tableView thats display search result), but that doesn't know about MyCell and that's why cell.cellMyCity is coming as nil in case of search, that means searchResultsTableView expect the default UITableViewCell and you are not setting anything for default cell like -

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

this whole scenario you can observe by changing you DataSource methods as bellow

    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
}

As far as Solution is concern, there could be two possible solution..

A). Don't use searchResultsTableView (provided by UISearchDisplayController) and display your search results in the same tableView that you have in your ViewController. For that what you can do is - listen to the UISearchBar delegates when user type some thing in UISearchBar get your result datasource (May be in different array) by Predicates and Display results in the same UITableView.

B). Customize UISearchDisplayController and use your custom cell (i.e MyCell) in searchResultsTableView

Comments