passer de la data depuis une uitableview via multiple segue

Bonjour,


Je fais actuellement passer de la data d'une UITableView vers un second controller avec un segue de cette façon (ça marche très bien) :



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

if ([segue.identifier isEqualToString:@showActivity]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];

Aiguillage *svc = (Aiguillage *)[segue destinationViewController];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
svc.item = object[@toObject];
svc.user = object[@fromUser];
}
}

Je voudrais à  présent inclure une condition pour distinguer si la data comporte :


- un objet + un user


- ou seulement un user


 


Selon le cas je souhaiterais les faire passer vers un second controller différent.


J'envisage donc d'utiliser 2 segues différents.


 


Mon code ci-dessous n'est pas bon (il ne se passe rien en tapant sur la cellule)


Je ne sais pas comment inclure la condition.



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

// condition
PFObject *objet = _object;
if (objet != nil) {

if ([[segue identifier] isEqualToString:@showObject]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];

// object + user
detail2ViewController *svc = (detail2ViewController *)[segue destinationViewController];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
svc.item = object[@toObject];
svc.user = object[@fromUser];

} else if ([[segue identifier] isEqualToString:@showUser]) {

// user only
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
friendActivityViewController *svc = (friendActivityViewController *)[segue destinationViewController];
PFObject *object = [self.objects objectAtIndex:indexPath.row];

svc.user = object[@fromUser];

}
}

}


NB : sur mon storyboard j'ai raccordé les deux segue+identifier depuis le controller lui-même (et pas depuis la cellule)


Quelqu'un aurait-il une idée qui pourrait m'aiguiller sur la manière d'écrire mon code ? Merci par avance pour votre aide !


 


 


Mots clés:
«1

Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur

    Je suppose que tu prévois deux boutons sur la cellule ? Sinon, comment savoir quel segue à  appeler ?


  • Bonjour Johanna,


    A priori la condition ci-dessous permet de savoir si la cellule comporte ou non un "objet"



    // condition
    PFObject *objet = _object;
    if (objet != nil) {


    en fonction je pensais diriger la data vers l'un ou l'autre des segue


    Je ne prévois pas de bouton sauf si indispensable ...


  • Ta condition, il faut la faire quand tu appelles performSegue(), pas dans le prepareForSegue(), car c'est trop tard.


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #5

    // TableViewController.m

    @interface TableViewController ()

    @property (strong, nonatomic) NSArray<PFObject *> *objects;

    @property (nonatomic) NSIndexPath *selectedCellIndexPath;

    @end


    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
    self.selectedCellIndexPath = indexPath;

    PFObject *selectedObject = [self.objects objectAtIndex:indexPath.row];

    if (selectedObject[@fromObject])
    {
    [self performSegueWithIdentifier:@showObject sender:self];
    }
    else
    {
    [self performSegueWithIdentifier:@showUser sender:self];
    }
    }

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
    PFObject *selectedObject = [self.objects objectAtIndex:self.selectedCellIndexPath.row];

    if ([segue.identifier isEqualToString:@showUser])
    {
    UserViewController *viewController = segue.destinationViewController;

    viewController.user = selectedObject[@toUser];

    return;
    }

    if ([segue.identifier isEqualToString:@showObject])
    {
    ObjectViewController *viewController = segue.destinationViewController;

    viewController.item = selectedObject[@fromObject];

    viewController.user = selectedObject[@toUser];
    }
    }
  • merci beaucoup Johanna !!


    Visiblement la data ne passe pas correctement, je vais tenter de voir où ça coince



    Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Key "username" has no data.
  • Trouvé, j'ai juste dû inverser les fromUser / toUser 



    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
    self.selectedCellIndexPath = indexPath;

    PFObject *selectedObject = [self.objects objectAtIndex:indexPath.row];

    if (selectedObject[@toObject])
    {
    [self performSegueWithIdentifier:@showObject sender:self];
    }
    else
    {
    [self performSegueWithIdentifier:@showUser sender:self];
    }
    }

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
    PFObject *selectedObject = [self.objects objectAtIndex:self.selectedCellIndexPath.row];

    if ([segue.identifier isEqualToString:@showUser])
    {
    friendActivityViewController *viewController = segue.destinationViewController;
    viewController.user = selectedObject[@fromUser];

    return;
    }

    if ([segue.identifier isEqualToString:@showObject])
    {
    detail2ViewController *viewController = segue.destinationViewController;

    viewController.item = selectedObject[@toObject];
    viewController.user = selectedObject[@fromUser];

    }
    }


    ça fonctionne nickel 


     


    Joanna Carter ===>  o:)   o:)


  • Juste pour ma culture et si vous avez le temps de me l'expliquer :


     


    Aurait-il été possible d'obtenir la même chose avec des boutons inclus sur les cellules ?


    Si oui comment les implanter ? Il me semble que sur des prototype cells l'opération n'est pas simple, peut-être avec des tags ?


  • Joanna CarterJoanna Carter Membre, Modérateur

    Il te faudrait une classe pour la cellule avec une protocole delegate qu'il faut capter dans la TableViewController et, d'une des méthodes recevantes, tu appellerais le bon segue.


     


    Donnes moi une heure et j'aurai du code.




  • Il te faudrait une classe pour la cellule avec une protocole delegate qu'il faut capter dans la TableViewController et, d'une des méthodes recevantes, tu appellerais le bon segue.


     


    Donnes moi une heure et j'aurai du code.




     


    Accordé 


    faudra que je songe à  t'embaucher 

  • Joanna CarterJoanna Carter Membre, Modérateur


    faudra que je songe à  t'embaucher 




     


     


    8--)



    // TableViewCell.h

    @class TableViewCell;


    @protocol TableViewCellDelegate <NSObject>

    - (void)didTapItemButtonInTableViewCell:(TableViewCell *)cell;

    - (void)didTapUserButtonInTableViewCell:(TableViewCell *)cell;

    @end


    @interface TableViewCell : UITableViewCell

    @property (strong, nonatomic) NSIndexPath *indexPath;

    @property (weak, nonatomic) id<TableViewCellDelegate> delegate;

    @end


    // TableViewCell.m

    @implementation TableViewCell

    - (IBAction)didTapUserButton
    {
    if (self.delegate)
    {
    [self.delegate didTapUserButtonInTableViewCell:self];
    }
    }

    - (IBAction)didTapItemButton
    {
    if (self.delegate)
    {
    [self.delegate didTapItemButtonInTableViewCell:self];
    }
    }

    - (void)prepareForReuse
    {
    self.indexPath = nil;

    self.delegate = nil;
    }

    @end


    // TableViewController.m

    @interface TableViewController () <TableViewCellDelegate>

    @property (strong, nonatomic) NSArray<PFObject *> *objects;

    @property (nonatomic) NSIndexPath *selectedCellIndexPath;

    @end


    @implementation TableViewController

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@cell forIndexPath:indexPath];

    cell.indexPath = indexPath;

    cell.delegate = self;

    return cell;
    }

    #pragma mark TableViewCellDelegate

    - (void)didTapItemButtonInTableViewCell:(TableViewCell *)cell
    {
    self.selectedCellIndexPath = cell.indexPath;

    [self performSegueWithIdentifier:@showObject sender:nil];
    }

    - (void)didTapUserButtonInTableViewCell:(TableViewCell *)cell
    {
    self.selectedCellIndexPath = cell.indexPath;

    [self performSegueWithIdentifier:@showUser sender:nil];
    }
  • génial !!


    Si je comprends bien il faut que je configure intégralement ma cellule sur la nouvelle classe TableViewCell ?

  • Joanna CarterJoanna Carter Membre, Modérateur

    Au moins, il faut ajouter les IBActions, le property indexPath et le property delegate à  ta propre classe ; et je te conseillerais de implementer la méthode prepareForReuse.


     


    Ou tu pourrais recommencer à  zero ; c'est à  toi de décider  :o




  • Au moins, il faut ajouter les IBActions, le property indexPath et le property delegate à  ta propre classe




    j'ai opté pour la première, ça marche super bien !!


    Tu viens de révolutionner une partie de mon appli, rien que ça ...

  • Dernière petite question concernant l'intégration d'un bouton sur la cellule.


    Si je souhaite effectuer une action avec le bouton et non un segue, comment puis-je le différencier ?


     


    Par exemple je fais le test avec une alertview (voir mon code ci-dessous), j'aimerais que l'alert apparaisse en tapant sur le bouton.


    Pour le moment ça me renvoie vers le segue "objet".



    - (void)didTapLikeButtonInTableViewCell:(TimeLineCell *)cell
    {
    self.selectedCellIndexPath = cell.indexPath;

    // action ?
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@Test
    message:[NSString stringWithFormat:NSLocalizedString(@ACTION,@%@ action test"), _object[@name]]
    delegate:nil
    cancelButtonTitle:@OK
    otherButtonTitles:nil, nil];
    [alert show];

    }

  • Joanna CarterJoanna Carter Membre, Modérateur

    Ce code se trouve dans la TableViewDelegate ? Tu as ajouté une autre méthode dans le TableViewCellDelegate ?



  • Ce code se trouve dans la TableViewDelegate ? Tu as ajouté une autre méthode dans le TableViewCellDelegate ?




     


    J'ai ajouté un autre bouton dans la TableViewCell :



    - (IBAction)didTapUserButton
    {
    if (self.delegate)
    {
    [self.delegate didTapUserButtonInTableViewCell:self];
    }
    }

    - (IBAction)didTapItemButton
    {
    if (self.delegate)
    {
    [self.delegate didTapItemButtonInTableViewCell:self];
    }
    }

    - (IBAction)didTapLikeButton
    {
    if (self.delegate)
    {
    [self.delegate didTapItemButtonInTableViewCell:self];
    }
    }

  • Joanna CarterJoanna Carter Membre, Modérateur

    Voilà  !!!


     


    Dans didTapLikeButton, tu appelles [self.delegate didTapItemButtonInTableViewCell: self] ; ce qui appellera le segue.


     


    Tu n'as pas ajouté une autre méthode au delegate protocol pour gérer le "like" ?




  • Voilà  !!!


     


    Dans didTapLikeButton, tu appelles [self.delegate didTapItemButtonInTableViewCell: self] ; ce qui appellera le segue.


     


    Tu n'as pas ajouté une autre méthode au delegate protocol pour gérer le "like" ?




    Oops je suis allé trop vite effectivement



    - (IBAction)didTapLikeButton
    {
    if (self.delegate)
    {
    [self.delegate didTapLikeButtonInTableViewCell:self];
    }
    }

    Effectivement le "like" n'a pas l'air d'être géré

  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #20

    Tu as mis les points d'arrêt dans le code pour que tu puisses trouver ou va le chemin d'exécution ?


     


    Ta méthode didTapLikeButtonInTableViewCell:  - elle est appelé ?


     


    Oh, et UIAlertView est deprecated


  • Joanna CarterJoanna Carter Membre, Modérateur

    Code pour UIAlertController



    - (void)didTapLikeButtonInTableViewCell:(TimeLineCell *)cell
    {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@Test message:@Action Test preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* ok = [UIAlertAction actionWithTitle:@OK style:UIAlertActionStyleCancel handler:nil];

    [alertController addAction:ok];

    [self presentViewController:alertController animated:YES completion:nil];
    }
  • (désolé un contre-temps hier m'a obligé à  m'arracher de mon Mac)


     


    J'essaye d'indiquer le nom de l'objet dans l'alertcontroller pour voir si le bouton détecte bien la cellule concernée, j'ai ajouté ceci à  partir de ton code ci-dessus :



    - (void)didTapLikeButtonInTableViewCell:(TimeLineCell *)cell
    {
    PFObject *selectedObject = [self.objects objectAtIndex:self.selectedCellIndexPath.row];
    PFObject *retrieveObject = [selectedObject objectForKey:@toObject];
    NSString *ObjectName = retrieveObject[@name];
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@Test message:ObjectName preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* ok = [UIAlertAction actionWithTitle:@OK style:UIAlertActionStyleCancel handler:nil];

    [alertController addAction:ok];

    [self presentViewController:alertController animated:YES completion:nil];
    }


    Malheureusement le nom qui apparait dans l'alert est constamment le nom de l'objet de la cellule la + récente ...

  • Joanna CarterJoanna Carter Membre, Modérateur
    C'est pou ça que j'ai mis l'indexPath dans la classe de cellule, qui est disponible dans ta méthode.
  • Okay


    Mais comment faire pour récupérer via le bouton les infos de l'objet associé à  la cellule (par exemple afficher le nom dans l'alert)


    Les cellules de la table sont construites comme ceci :



    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
    {
    TimeLineCell *cell = [tableView dequeueReusableCellWithIdentifier:@Cell forIndexPath:indexPath];

    cell.indexPath = indexPath;
    cell.delegate = self;



    de cette manière je peux retrouver les infos du PFObject , par exemple pour le nom  :



     PFObject *retrieveobject = [object objectForKey:@toObject];

        UILabel *nameLabel = (UILabel*) [cell viewWithTag:5];
        nameLabel.text = [retrieveobject objectForKey:@name];

  • Joanna CarterJoanna Carter Membre, Modérateur

    Tu étais déjà  presque là  :



    - (void)didTapLikeButtonInTableViewCell:(TimeLineCell *)cell
    {
    PFObject *selectedObject = [self.objects objectAtIndex:cell.indexPath.row]; // regardes bien cette ligne

    PFObject *retrieveObject = [selectedObject objectForKey:@toObject];

    NSString *objectName = retrieveObject[@name];

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@Test message:objectName preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* ok = [UIAlertAction actionWithTitle:@OK style:UIAlertActionStyleCancel handler:nil];

    [alertController addAction:ok];

    [self presentViewController:alertController animated:YES completion:nil];
    }


  •  


    Tu étais déjà  presque là  :



    - (void)didTapLikeButtonInTableViewCell:(TimeLineCell *)cell
    {
    PFObject *selectedObject = [self.objects objectAtIndex:cell.indexPath.row]; // regardes bien cette ligne



    effectivement , yeees

  • Bonjour,


    Je reviens sur ce topic au sujet des buttons intégrés sur une cellule.


    J'ai intégré sur mon uitableview un uibarbuttonitem, l'outlet est bien appelé et relié :



    @property (weak, nonatomic) IBOutlet UIBarButtonItem *addFriendsButton;

    ce bouton est lié vers un autre controller via storyboard segue (sur lequel je ne fais pas passer de data)


     


    Mon problème : lorsque la table est vide (uniquement) et lorsque j'appuie sur cet UIBarButtonItem l'appli plante avec le message d'erreur suivant :



    *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'

    Lorsque sur la table apparait au moins 1 cellule, il n'y a plus de crash. Je pense que ce problème est lié au fait d'avoir intégré une cellule au moyen d'une autre class (avant de le faire je n'avais pas ce problème). Cependant je ne vois pas comment le résoudre... auriez-vous une idée ?


  • Pourquoi tu fais pas juste un test pour voir si la table est vide lors de l'appuie sur ton UIBarButtonItem ?


    Si elle est vide, tu ne lance pas la suite..


     


    (Je ne connais pas ton programme donc peut-être que tu as besoin de lancer la suite quand même ^^)




  • Pourquoi tu fais pas juste un test pour voir si la table est vide lors de l'appuie sur ton UIBarButtonItem ?


    Si elle est vide, tu ne lance pas la suite..


     


    (Je ne connais pas ton programme donc peut-être que tu as besoin de lancer la suite quand même ^^)




    Oui j'y ai pensé mais effectivement j'ai besoin de lancer la suite quand même (indispensable)

  • Dans tout les cas, tu dois avoir un soucis de conception..


    Parce que t'essaie d'appeler un index dans un array qui est vide.. c'est pas logique ^^


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #31
    Tu peux nous montrer le code où tu récupères l'objet de la liste ?
Connectez-vous ou Inscrivez-vous pour répondre.