web-dev-qa-db-fra.com

Classe de registre UITableViewCell personnalisée dans Swift

Dans mon application, je remplis la table sur la base du tableau. La table utilise UITableViewCell personnalisé. Tout fonctionne bien, la table est remplie. Ensuite, j'ajoute un contrôleur d'affichage de recherche à mon UITableViewController, aucun code en écriture pour gérer la recherche, il suffit d'ajouter le contrôleur. Lorsque vous exécutez l'application, la table est toujours remplie. Mais si j'essaie de cliquer sur la barre de recherche, j'obtiens le message d'erreur suivant:

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'

J'essaie d'ajouter à ma fonction viewDidLoad dans la ligne UITableViewController:

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

Lancez l'application et obtenez immédiatement l'erreur:

fatal error: unexpectedly found nil while unwrapping an Optional value

En ligne cell.cellMyCity.text = cellText

Qu'est-ce que je fais mal?

Ceci est ma classe personnalisée 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)

}
}

C'est le code de la cellule:

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
}

Propriété dans TableViewCell: enter image description hereenter image description hereenter image description here

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

enter image description here

16
Alexey Nakhimov

Comme le suggère l’erreur, vous obtenez votre cell ou UITestFieldnil et Swift ne prend pas en charge l’appel de méthode sur un objet nil, c’est la raison pour laquelle vous obtenez un crash. vous pouvez empêcher le crash en vérifiant que l'objet est nul ou non comme ci-dessous 

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

MODIFIER

Je pense que j'ai quel est le problème ici ...

Vous avez un glisser-déposer UISearchBar dans votre storyboard, ainsi, par défaut, toutes les sources de données et le délégué sont définis sur votre contrôleur. Par exemple, ViewController (classe dans laquelle vous écrasez les méthodes UITableView DataSource) et ViewController vous enregistrez la classe MyCell comme votre classe de personnalisation . Ainsi, votre tableView affiche parfaitement, mais lorsque vous tapez quelque chose dans UISearchBar, les mêmes méthodes DataSource (ViewController) sont appelées et là aussi, vous enregistrez MyCell pour searchResultsTableView (UISearchDisplayController tableView qui affiche le résultat de la recherche), mais cela ne signifie Si vous ne connaissez pas MyCell, c’est pourquoi cell.cellMyCity est nul en cas de recherche; cela signifie que searchResultsTableView s’attend à la valeur par défaut UITableViewCell et que vous ne définissez rien comme cellule par défaut - 

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

tout ce scénario que vous pouvez observer en changeant vos méthodes DataSource comme ci-dessous 

    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
}

En ce qui concerne La solution concerne, il pourrait y avoir deux solutions possibles.

UNE). N'utilisez pas searchResultsTableView (fourni par UISearchDisplayController) et affichez vos résultats de recherche dans la même tableView que vous avez dans votre ViewController. Pour cela, écoutez les délégués UISearchBar lorsque l'utilisateur saisit quelque chose dans UISearchBar obtenir votre source de données de résultats (peut être dans un tableau différent) par Prédicats et afficher les résultats dans la même UITableView.

B) Personnalisez UISearchDisplayController et utilisez votre cellule personnalisée (i.e MyCell) dans searchResultsTableView

8
Suryakant

ce que j'ai fait pour que cela fonctionne ressemble à ceci:

class MainViewController: UIViewController {

    // ...

    @IBOutlet var tableView: UITableView

    override func viewDidLoad() {
        super.viewDidLoad()

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

        // ...
    }

    // ...

}

REMARQUE: Si j'utilise la méthode –registerClass(_: forCellReuseIdentifier:), le fichier xib ne sera pas chargé. Par conséquent, l'interface personnalisée réelle n'apparaîtra que si vous ajoutez le contenu par programme à la cellule. si vous souhaitez charger l'interface à partir d'un fichier nib, vous devez enregistrer la cellule avec son nib.


conforme aux protocoles essentiels:

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
    }

}

et la classe de cellules personnalisée était une classe très générique avec un nom significatif comme 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
    }

}

avec une interface assez aléatoire:

random custom interface

et ces paramètres de classe personnalisée et identifiant de réutilisation :

custom classreuse identifier


et le résultat final sur mon écran est comme je m'y attendais avec 3 lignes:

the final result in practice

REMARQUE: pour personnaliser davantage les cellules personnalisées, vous devrez peut-être étendre le code ci-dessus.

METTRE À JOUR

avec UISearchBar, le résultat final serait le suivant:

with Search Bar

18
holex

L'ajout de self avant tableView résout les problèmes suivants:

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

assurez-vous de supprimer la classe register si vous utilisez le storyboard car il écrasera le storyboard et tous les liens externes qui lui sont associés.

veuillez vérifier https://stackoverflow.com/a/26350795/4453583

ça marche pour moi =)

2
Sunny Hardasani

N'oubliez pas d'enregistrer la cellule pour toute tableView l'utilisant, y compris searchDisplayController.tableView.

1
JimmyB