web-dev-qa-db-fra.com

Poussez le passage de UITableViewCell à ViewController dans Swift

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
        }
    }
11
Jack

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
        }
    }
}
20
ergoon

Les étapes suivantes devraient résoudre votre problème. Si non, s'il vous plaît faites le moi savoir.

  1. Supprimez votre implémentation tableView(tableView, didSelectRowAtIndexPath:).

  2. Assurez data sur RestaurantViewController avoir le type NSDictionary!

  3. 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
            }
        }
    }
    
4
Tammo Freese

Lien Dropbox vers le répertoire stack3

  1. 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.

  2. 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. 

  3. 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.

  4. 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.

  5. 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)

    1. Enfin, je vous recommande de vérifier l'inspecteur de connexions (pour la cellule d'affichage du tableau dans le premier contrôleur) pour vous assurer qu'il existe une transition vers le second contrôleur. Si vous maintenez la touche Ctrl enfoncée correctement, l'invite de confirmation doit apparaître, ainsi qu'une entrée dans l'inspecteur de connexions.

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

}

}
3
Syed Tariq

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.

2
Christopher Whidden

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.

1
KyleMassacre

Essayez de créer des cellules comme celle-ci dans votre méthode cellForRow:

let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath)
1
Starscream

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
    }
}
0
João Henrique

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)!]
    }
}
0
Chamath Jeevan