Je rencontre des problèmes avec mes UITableViewCells. J'ai connecté mon UITableView à une API pour remplir mes cellules.
Ensuite, j'ai créé une fonction qui saisit le indexPath.row
pour identifier quel objet JSON à l'intérieur du tableau devrait être envoyé à la RestaurantViewController
.
Lien vers mon projet Xcode pour faciliter le débogage et la résolution de problèmes
Voici comment mon petit extrait cherche à définir les "clics de ligne" sur une variable globale.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
i = indexPath.row
}
Et voici ma fonction prepareForSegue()
qui devrait relier mon Push-segue à la RestaurantViewController
.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
Et voici comment je me suis séparé de la UITableViewCell
Voici mon résultat, j'ai essayé de cliquer sur chacune de ces cellules mais je ne serai pas poussé vers un autre viewController ... Je ne reçois pas non plus d'erreur. Qu'est-ce qui ne va pas ici?
Des solutions éprouvées qui ne fonctionneront pas
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let vc = segue.destinationViewController as RestaurantViewController
//let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
Le problème est que vous ne gérez pas vos données correctement ... Si vous examinez votre tableau currentResponse
, vous verrez qu'il contient les NSDictionaries, mais que dans votre prepareForSegue
, vous essayez de convertir un NSDictionary en un NSArray, ce qui rendra le crash de l'application.
Changez la variable data
dans RestaurantViewController
en un NSDictionary et changez votre prepareForSegue
pour passer un NSDictionary
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = redditListTableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
Les étapes suivantes devraient résoudre votre problème. Si non, s'il vous plaît faites le moi savoir.
Supprimez votre implémentation tableView(tableView, didSelectRowAtIndexPath:)
.
Assurez data
sur RestaurantViewController
avoir le type NSDictionary!
Déterminez la ligne sélectionnée dans prepareForSegue
:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = tableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
Lien Dropbox vers le répertoire stack3
J'ai du mal à comprendre pourquoi votre logiciel est très différent d'une structure tableview standard à 2 niveaux. J'ai donc codé un court exemple auquel vous pouvez accéder à partir de ce lien. J'ai également inclus le code de source ci-dessous.
Le programme imite ce que vous avez (autant que je l'ai compris). Le contrôleur de table 1 passe au contrôleur de table 2 à partir de la cellule tableview. Je n'ai eu aucun problème avec segue-ing. Notez que je n'ai ni besoin d'augmenter le livre de contes pour lancer la transition.
J'ai intégré les deux contrôleurs dans les contrôleurs de navigation. Mon expérience est que cela permet d'économiser beaucoup d'efforts pour configurer la navigation.
Alternativement, j'aurais pu faire glisser le contrôle du premier symbole TableViewController en haut de l'écran vers le second contrôleur et configurer la séquence.
J'ai utilisé une variable globale (selectedRow) bien que ce ne soit pas une pratique recommandée. Mais vous utilisez aussi facilement prepareForSegue pour définir une variable dans RestaurantTableViewController (je montre un exemple)
Malheureusement, je n'arrive pas à obtenir le code correctement.
import UIKit
var selectedRow = -1
class TableViewController: UITableViewController {
var firstArray = ["Item1","Item2","Item3","Item4"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return firstArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = firstArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let vc = segue.destinationViewController as RestaurantTableViewController
// can write to variables in RestaurantTableViewController if required
vc.someVariable = selectedRow
}
}
import UIKit
class RestaurantTableViewController: UITableViewController {
var secondArray = ["Item 2.1", "Item 2.2", "Item 2.3", "Item 2.4"]
var someVariable = -1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return secondArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = secondArray[indexPath.row]
if indexPath.row == selectedRow {
cell.textLabel!.text = cell.textLabel!.text! + " SELECTED"
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
}
J'ai remarqué que dans votre capture d'écran de votre scénario, la séquence connecte le premier prototype de cellule à la RestaurantViewController
. Cette cellule prototype ressemble au style "Basic" de cellule avec un accessoire indicateur de divulgation à droite. Mais regardez la capture d'écran de votre application en cours d'exécution. Le tableau contient des cellules qui semblent être du style de cellule "Sous-titre" sans accessoire indicateur de divulgation à droite.
La raison pour laquelle votre séquence ne se déclenche jamais, peu importe ce que vous faites, est que la séquence est configurée uniquement pour fonctionner avec une cellule prototype spécifique, mais que cette cellule prototype n'est jamais utilisée lorsque vous remplissez la table. Quoi que vous fassiez dans tableView:cellForRowAtIndexPath:
, vous n'utilisez pas la cellule prototype que vous voulez.
@Starscream a la bonne idée de mettre en file d'attente la bonne cellule avec le bon identifiant et de la faire correspondre à l'identifiant de la cellule prototype dans Interface Builder. Le crash que vous obtenez même après avoir fait cela pourrait être dû au problème précédent mentionné dans les commentaires ci-dessus. Votre séquence dans le storyboard indique clairement une UITableViewController
. Votre code dans prepareForSegue:sender:
devrait être let vc = segue.destinationViewController as RestaurantViewController
, tant que RestaurantViewController
est une sous-classe de UITableViewController
. Vous allez tomber en panne si vous essayez de le lancer en tant que UINavigationController
. Assurez-vous également que la classe pour la destination UITableViewController
dans le storyboard est répertoriée en tant que RestaurantController
dans le volet Inspecteur d'identité. Vous allez tomber en panne si votre programme compile en pensant que le storyboard ne contient qu'une variable UITableViewController
générique.
Pour en revenir au problème initial plus, je ne sais pas comment vous avez implémenté tableView:cellForRowAtIndexPath:
, qui pourrait être crucial. Peut-être que ce n'est pas si simple. Vous envisagez peut-être de gérer de nombreuses cellules prototypes ou de générer des cellules personnalisées lors de l'exécution. Dans ce cas, une façon de vous simplifier la tâche consiste à effectuer la programmation par séquence lorsque l'utilisateur appuie sur une cellule. Au lieu d’utiliser un prototype de cellule spécifique, définissez dans l’ordre une connexion provenant de "Restauranger nära mig" UITableViewController
allant à RestaurantViewController
. (Connectez-vous à Interface Builder en maintenant la touche Ctrl enfoncée tout en cliquant sur l'icône du contrôleur d'affichage de la table située en haut de la première sur le corps de la seconde). Vous devez attribuer à cette séquence un identifiant dans le volet Inspecteur d'attributs pour que cela soit utile. Disons que c'est "toRestaurant"
. Ensuite, à la fin de votre méthode tableView:didSelectRowAtIndexPath:
, insérez cette ligne de code: self.performSegueWithIdentifier("toRestaurant", sender: self)
. Maintenant, quelle que soit la cellule sélectionnée dans le tableau, cette séquence sera toujours déclenchée pour vous.
Je pars sur un coup de tête ici car je viens d'entrer dans Swift pour le moment, mais la façon dont je le fais dans ma prepareForSegue()
ressemble à ceci:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
//notice I changed [i] to [index!.row]
vc.data = currentResponse[index!.row] as NSArray
}
}
Pour moi, cela ressemble à ce que vous appelez la variable i, qui ressemble à une variable privée dans une méthode de votre classe. Vous pouvez faire quelque chose comme @Syed Tariq avec la variable selectRow
et le définir au-dessus de votre class SomeController: UIViewController /*, maybe some more here? */ {
, puis signer la variable dans votre
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
comme ci-dessus mais les deux méthodes devraient plutôt bien fonctionner.
Essayez de créer des cellules comme celle-ci dans votre méthode cellForRow
:
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath)
J'ai eu le même problème et j'ai trouvé la solution:
performSegueWithIdentifier ("toViewDetails", expéditeur: auto)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cellnumber = procMgr.processos[indexPath.row].numero
println("You selected cell #\(indexPath.row)")
println(cellnumber)
performSegueWithIdentifier("toViewDetails", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toViewDetails" {
let DestViewController : ViewDetails = segue.destinationViewController as! ViewDetails
}
}
Vous devrez peut-être obtenir l'index de cellule sélectionné de la vue UItable. Le code ci-dessous utilise l'index de cellule sélectionné (UItableview.indexPathForSelectedRow) pour obtenir un élément correct du tableau.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "seguaVisitCardDetial" {
let viewController = segue.destinationViewController as! VCVisitCardDetial
viewController.dataThisCard = self.listOfVisitCards[(tblCardList.indexPathForSelectedRow?.row)!]
}
}