Utilisez la méthode didSelectRowAtIndexPath ou prepareForSegue pour UITableView?

101

J'utilise des storyboards et j'ai un UITableView. J'ai une configuration de segue qui pousse de ma table au détail VC. Mais quelle méthode dois-je utiliser pour gérer cela? Je vais devoir passer quelques objets à la vue détaillée. Mais est-ce que j'utilise didSelectRowAtIndexou -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender?

Jon
la source

Réponses:

199

Si vous utilisez, prepareForSegue:sender:vous n'aurez pas autant à changer si vous décidez plus tard de déclencher la transition à partir d'un contrôle en dehors de la vue de table.

Le prepareForSegue:sender:message est envoyé au contrôleur de vue actuel, je suggère donc quelque chose comme ceci:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Assume self.view is the table view
    NSIndexPath *path = [self.tableView indexPathForSelectedRow];
    DetailObject *detail = [self detailForIndexPath:path];
    [segue.destinationViewController setDetail:detail];
}

Dans Swift:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let path = self.tableView.indexPathForSelectedRow()!
    segue.destinationViewController.detail = self.detailForIndexPath(path)
}
Rob Mayoff
la source
1
Ok, pouvez-vous donner un exemple de la façon de l'implémenter en passant un objet basé sur indexPath.
Jon
4
ne devrait pas self.viewêtre juste senderici? Je ne pouvais même pas me rendre [self.view indexPathForSelectedRow]au travail, je devais le faire[sender indexPathForSelectedRow];
ladookie
Comment feriez-vous cela dans Swift?
Utilisateur du
@robmayoff Merci d'avoir mis à jour ceci pour Swift. J'ai fait quelques légères modifications pour refléter les récents changements de langue. J'espère que cela aide certains autres
Zack Shapiro
Il est étrange de tableView.indexPathForSelectedRow()contenir la valeur correcte lors de l' prepareFroSegue...appel: tableView(_:didSelectrowAtIndexPath:)n'est appelé que plus tard.
Nicolas Miari
5

Je l'ai fait et ça a marché

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    NSLog(@"Row Selected = %i",indexPath.row);

    [self performSegueWithIdentifier:@"testID" sender:self.view];    
}
Rohit Mandiwal
la source
11
Cela n'a pas de sens. Vous devez soit utiliser le segue OU le délégué de vue de table. Créez simplement une séquence à partir de la cellule et elle effectuera automatiquement la même chose que vous avez faite sans écrire de code.
Yariv Nissim
3
comment attribuer une séquence à une cellule sans didSelectRow?
Morkrom
3

Lorsque l'expéditeur est UITableViewCell, vous pouvez demander à UITableView d'interroger l'indexPath de la cellule.

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let cell = sender as? UITableViewCell {
            let indexPath = self.tableView.indexPathForCell(cell)!
            assert(segue.destinationViewController.isKindOfClass(DetailViewController))
            let detailViewController = segue.destinationViewController as! DetailViewController
            detailViewController.item = self.items[indexPath.row] // like this
        }
    }
Kaz Yoshikawa
la source
1

si votre propriété tableView est dans une autre classe et que vous n'avez qu'une seule section , vous pouvez utiliser la tagpropriété pour stocker la ligne de la cellule comme:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];

     cell.tag = indexPath.row;

     return cell;
}

Et puis vous pouvez y accéder car senderc'est la même cellule avec la valeur de ligne dans sa balise:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    MyDestinationViewController *destinationViewController = segue.destinationViewController;
    destinationViewController.myProperty = [tableViewElementsArray objectAtIndex:[sender tag]]; // sender will be your cell 
}
Laszlo
la source
1

self.tableView.indexPathForSelectedRowrenvoie la cellule sélectionnée, mais pas la cellule de l'expéditeur, par exemple la cellule de l'expéditeur n'est pas sélectionnée (action accessoire), ou en cas de sélection multiple. Le meilleur moyen est d'obtenir indexPath pour l'expéditeur de segue:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    __auto_type itemViewController = (id<ItemViewController>)segue.destinationViewController;
    itemViewController.senderIndexPath = [self.tableView indexPathForCell:sender];
}

Dans Swift:

protocol ItemViewController {
    var senderIndexPath : IndexPath? { get set }
    var selectedIndexPaths : [IndexPath]? { get set }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if  let cell = sender as? UITableViewCell,
        var itemViewController = segue.destination as? ItemViewController {
        itemViewController.senderIndexPath = tableView.indexPath(for: cell)
        itemViewController.selectedIndexPaths = tableView.indexPathsForSelectedRows
    }
}
Stanislav P.
la source
0

Si vous utilisez, prepareForSegue:vous pouvez vérifier qui est l'expéditeur et exécuter un code différent

Par exemple dans swift

override func prepareForSegue(segue: UiStoryboardSegue, sender: AnyObject?)
{
   var senderIsTableviewCell:Bool! = sender?.isKindOfClass(UITableViewCell)

   if senderIsTableviewCell
   {
       //do something
   }
}
Eugène
la source
2
Faites simplement : si laissez tableViewCell = sender as? UITableViewCell {// faire quelque chose} . Si l'expéditeur ne peut pas être converti en UITableViewCell, "faire quelque chose" ne s'exécutera pas.
mbeaty