[réglé] Récupérer le titre d'un UIButton située dans un UITableView

Jean75Jean75 Membre
novembre 2014 modifié dans API UIKit #1

Bonjour à  tous,


 


Je vous explique, j'ai une UITableView, avec x UITableViewCell.


 


Cette cellule se compose de 2 UILabel et 3 UIButton.


 


J'ai bien entendu un IBAction sur chacun de mes boutons.


 


Parmi mes 3 actions, je doit effectuer 2 appels sur les numéros (fixe et portable) contenus dans le titre de mes 2 boutons, et envoyer un mail à  l'adresse dans le titre de mon 3e bouton


 


Ce que j'aimerais faire en réalité c'est récupérer le titre du bouton à  l'index n pour ensuite interagir dessus


 


Exemple: 



NSString* numPhone = [NSString stringWithFormat:@telprompt://%@",monBouton.currentTitle;
[UIApplication.sharedApplication openURL:[NSURL URLWithString:numPhone]];

Quelqu'un saurait me dire comment faire s'il vous plait ?


 


En vous remerciant d'avance


«1

Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2014 modifié #2

    C'est pas une bonne idée de garder les données dans le texte des boutons ou autre contrôles. Les données de chaque cellule devraient être dans un modèle, un pour chaque cellule, dans une liste tenue dans le viewcontroller.


  • Après ces données sont également dans un dictionnaire, mais le problème reste le même, en effet je doit récupérer l'objet a l'index n ayant pour clé "Blabla"


     


    Exemple de ce que je fais pour assigner le contenu dans le titre du bouton:



    [cell.telPortableContact setTitle:listeContacts[indexPath.row][@MobilePhone] forState:UIControlStateNormal];
  • Joanna CarterJoanna Carter Membre, Modérateur

    Tu as une classe Contact ?


     


    Lorsque tu crées la cellule, tu peux passer le contact vers la cellule, du coup, tu pourrais accéder la numéro dans le IBAction dans la cellule.

  • Non je n'ai pas de classe Contact.


     


    Pas compris la 2nde ligne par contre


  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2014 modifié #6

    Qu'est-ce que tu as dans chacun de tes "listeContacts" ?


  • listeContact est un tableau qui contient les informations suivants:


    • ID (obligatoire)
    • Nom & prénom (obligatoire)
    • Téléphone fixe (facultatif)
    • Téléphone portable (facultatif)
    • Adresse email (facultatif)
  • Joanna CarterJoanna Carter Membre, Modérateur

    D'accord - attends, je fais un projet demo


  • Ok, merci Joanna :)


  • Joanna CarterJoanna Carter Membre, Modérateur

    OK - code :



    // Contact.h

    @interface Contact : NSObject

    @property (nonatomic) NSUInteger ID;

    @property (copy, nonatomic) NSString *nom;

    @property (copy, nonatomic) NSString *prenom;

    @property (copy, nonatomic) NSString *telephoneFixe;

    @property (copy, nonatomic) NSString *telephonePortable;

    @property (copy, nonatomic) NSString *adresseEmail;

    @end


    // ContactCell.h

    @class Contact;


    @interface ContactCell : UITableViewCell

    @property (weak, nonatomic) Contact *contact;

    @end


    // ContactCell.m

    #import "ContactCell.h"
    #import "Contact.h"


    @interface ContactCell ()

    @property (weak, nonatomic) IBOutlet UIButton *boutonTelelphoneFixe;

    @property (weak, nonatomic) IBOutlet UIButton *boutonTelelphonePortable;

    - (IBAction)boutonFixeTouchUpInside:(UIButton *)sender;

    - (IBAction)boutonPortableTouchUpInside:(UIButton *)sender;

    @end


    @implementation ContactCell

    - (void)setContact:(Contact *)contact
    {
    _contact = contact;

    [self.boutonTelelphoneFixe setTitle: _contact.telephoneFixe forState:UIControlStateNormal];

    [self.boutonTelelphonePortable setTitle: _contact.telephonePortable forState:UIControlStateNormal];
    }

    - (void)boutonFixeTouchUpInside:(UIButton *)sender
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt://%@", self.contact.telephoneFixe];

    [UIApplication.sharedApplication openURL:[NSURL URLWithString:numPhone]];
    }

    - (void)boutonPortableTouchUpInside:(UIButton *)sender
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt://%@", self.contact.telephonePortable];

    [UIApplication.sharedApplication openURL:[NSURL URLWithString:numPhone]];
    }

    @end


    // ViewController.m

    #import "ViewController.h"
    #import "Contact.h"
    #import "ContactCell.h"


    @interface ViewController ()

    @property (strong, nonatomic) NSArray *listeContacts;

    @end


    @implementation ViewController

    - (NSArray *)listeContacts
    {
    if (!_listeContacts)
    {
    // données de test
    Contact *contact1 = [[Contact alloc] init];

    contact1.telephoneFixe = @01 23 45 67 89;

    contact1.telephonePortable = @06 23 45 67 89;

    Contact *contact2 = [[Contact alloc] init];

    contact2.telephoneFixe = @01 98 76 54 32;

    contact2.telephonePortable = @06 98 76 54 32;

    _listeContacts = @[;contact1, contact2];
    }

    return _listeContacts;
    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    return self.listeContacts.count;
    }

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

    contactCell.contact = self.listeContacts[indexPath.row];

    return contactCell;
    }

    @end
  • Joanna CarterJoanna Carter Membre, Modérateur

    Pour la sécurité :



    - (void)boutonFixeTouchUpInside:(UIButton *)sender
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt:%@", self.contact.telephoneFixe];

    NSURL *numPhoneURL = [NSURL URLWithString:numPhone];

    if ([[UIApplication sharedApplication] canOpenURL:numPhoneURL])
    {
    [[UIApplication sharedApplication] openURL:numPhoneURL];
    }
    }

    - (void)boutonPortableTouchUpInside:(UIButton *)sender
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt:%@", self.contact.telephonePortable];

    NSURL *numPhoneURL = [NSURL URLWithString:numPhone];

    if ([[UIApplication sharedApplication] canOpenURL:numPhoneURL])
    {
    [[UIApplication sharedApplication] openURL:numPhoneURL];
    }
    }
  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2014 modifié #12

    Encore mieux :



    - (void)composerNumeroPhone:(NSString *)numeroPhone
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt:%@", numeroPhone];

    NSURL *numPhoneURL = [NSURL URLWithString:numPhone];

    if ([[UIApplication sharedApplication] canOpenURL:numPhoneURL])
    {
    [[UIApplication sharedApplication] openURL:numPhoneURL];
    }
    }

    - (void)boutonFixeTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact.telephoneFixe];
    }

    - (void)boutonPortableTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact.telephonePortable];
    }



  • // ContactCell.h

    @class Contact;


    @interface ContactCell : UITableViewCell

    @property (weak, nonatomic) Contact *contact;

    @end

    @Joanna pourquoi tu l'as mis l'objet modèle en weak ?

  • Joanna CarterJoanna Carter Membre, Modérateur

    Parce que il y a déjà  une référence strong dans la liste ; c'est pas nécessaire d'en avoir plus  :)


  • Bon j'ai bien regardé et analysé ton code, et j'ai constaté quelques trucs:


     


    - La méthode "setContact" n'est jamais utilisée, quelle est donc l'intérêt de l'avoir crée ?


    - Je ne vois pas en quoi ta manière de faire solution le problème. En effet comment fait on la différence entre le clic sur le bouton de la cellule 1 et celui sur la cellule 2, à  aucun moment je vois un quelconque index qui corresponds à  celui de la cellule




  • Parce que il y a déjà  une référence strong dans la liste ; c'est pas nécessaire d'en avoir plus  :)




    Je ne pense pas que c'est une bonne pratique. Je pend que la cellule doit avoir une référence forte vers l'objet modèle qu'elle affiche, sinon c'est comme avoir des dépendance cachées un peut partout. 


     


    Et si tu passe l'objet  modèle "Contact" à  un contrôleur détail, qui va afficher le détail "Contact", tu le mettras aussi en weak dans ce cas puisque il est déjà  dans la liste ( en strong), comme la cellule ?


     


     




    Bon j'ai bien regardé et analysé ton code, et j'ai constaté quelques trucs:


     


    - La méthode "setContact" n'est jamais utilisée, quelle est donc l'intérêt de l'avoir crée ?


    - Je ne vois pas en quoi ta manière de faire solution le problème. En effet comment fait on la différence entre le clic sur le bouton de la cellule 1 et celui sur la cellule 2, à  aucun moment je vois un quelconque index qui corresponds à  celui de la cellule




     


    Surement elle t'as pas fourni un code à  100 % fonctionnel, mais juste comment faire proprement et c'est à  toi de l'adapter.

  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2014 modifié #17


    - La méthode "setContact" n'est jamais utilisée, quelle est donc l'intérêt de l'avoir crée ?




     


    Mais sûrement elle est utilisée. C'est le setter pour la propriété contact. Lorsqu'on écrit contactCell.contact = ..., l'execution passe par cette méthode.


     




    - Je ne vois pas en quoi ta manière de faire solution le problème. En effet comment fait on la différence entre le clic sur le bouton de la cellule 1 et celui sur la cellule 2, à  aucun moment je vois un quelconque index qui corresponds à  celui de la cellule




     


    Parce que chaque cellule s'occupe de gérer les actions de ses propres boutons et chaque cellule tient référence a son propre Contact.


     


    Vois le code pour -tableView:cellForRowAtIndexPath:




  •  


    Pour la sécurité :



    - (void)boutonFixeTouchUpInside:(UIButton *)sender
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt:%@", self.contact.telephoneFixe];

    NSURL *numPhoneURL = [NSURL URLWithString:numPhone];

    if ([[UIApplication sharedApplication] canOpenURL:numPhoneURL])
    {
    [[UIApplication sharedApplication] openURL:numPhoneURL];
    }
    }

    - (void)boutonPortableTouchUpInside:(UIButton *)sender
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt:%@", self.contact.telephonePortable];

    NSURL *numPhoneURL = [NSURL URLWithString:numPhone];

    if ([[UIApplication sharedApplication] canOpenURL:numPhoneURL])
    {
    [[UIApplication sharedApplication] openURL:numPhoneURL];
    }
    }



     


     




     


    Encore mieux :



    - (void)composerNumeroPhone:(NSString *)numeroPhone
    {
    NSString* numPhone = [NSString stringWithFormat:@telprompt:%@", numeroPhone];

    NSURL *numPhoneURL = [NSURL URLWithString:numPhone];

    if ([[UIApplication sharedApplication] canOpenURL:numPhoneURL])
    {
    [[UIApplication sharedApplication] openURL:numPhoneURL];
    }
    }

    - (void)boutonFixeTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact.telephoneFixe];
    }

    - (void)boutonPortableTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact.telephonePortable];
    }



     


    On est bien d'accord que je doit mettre ça dans mon ViewController s'il te plait ?

  • Joanna CarterJoanna Carter Membre, Modérateur

    Pas du tout. Si tu regardes le code original, tu verras qu'il se situe dans la classe ContactCell.


  • Joanna CarterJoanna Carter Membre, Modérateur

    Est-ce que tu voudrais que je t'envoie le projet par MP ?


  • C'est à  voir,


     


    J'ai repris ce que tu as fait, en essayant de comprendre.


     


    Ton projet est simple, donc ça marche plutôt bien, mais le mien est un peu plus complexe avec notamment un dictionnaire



    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *simpleTableIdentifier = @CelluleContact;


    ContactCell *contactCell = [tabView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

    if (contactCell == nil) {
    contactCell = [[ContactCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
    }


    cell.typeContact.text=_typeContact[[listeContacts[indexPath.row][@IDDuContact]integerValue]];
    cell.nomPrenomContact.text=listeContacts [indexPath.row][@NomEtPrenom];
    if([listeContacts[indexPath.row][@TelFixe] isEqualToString:@""])
    {
    [cell.telFixeContact setTitle:@- forState:UIControlStateNormal];
    cell.telFixeContact.enabled = NO;
    }
    else
    {
    [cell.telFixeContact setTitle:listeContacts[indexPath.row][@TelFixe] forState:UIControlStateNormal];
    cell.telFixeContact.enabled = YES;
    }
    if([listeContacts[indexPath.row][@TelPortable] isEqualToString:@""])
    {
    [cell.telPortableContact setTitle:@- forState:UIControlStateNormal];
    cell.telPortableContact.enabled = NO;
    }
    else
    {
    [cell.telPortableContact setTitle:listeContacts[indexPath.row][@TelPortable] forState:UIControlStateNormal];
    cell.telPortableContact.enabled = YES;
    }
    if([listeContacts[indexPath.row][@Email] isEqualToString:@""])
    {
    [cell.emailContact setTitle:@- forState:UIControlStateNormal];
    cell.emailContact.enabled = NO;
    }
    else
    {
    [cell.emailContact setTitle:listeContacts[indexPath.row][@Email] forState:UIControlStateNormal];
    cell.emailContact.enabled = YES;
    }

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
    }

    Voila mon ancien code, qui fonctionnait très bien.


     


    J'aimerais le réadapter avec ce que tu as fait, mais j'avoue avoir un peu de mal, vu que je débute.


  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2014 modifié #22

    Je ne sais pas où tu as appris à  coder mais ce que tu as fait, c'est pas le bon code par rapport aux APIs récents.


     


    Tout d'abord, est-ce que tu as créé un xib ou utilisé le storyboard pour dessiner la cellule ?


     


    Si tu utilises le storyboard, c'est pas nécessaire de verifier si la cellule renvoyé par -dequeueReusableCellWithIdentifier: est nil ou non - c'est garanti.


     


    Si tu utilises un xib, on peut "enregistrer" le xib avec le tableView est ce sera comme avec un storyboard - la cellule renvoyé par -dequeueReusableCellWithIdentifier: ne sera jamais nil.


     


    à‰videmment, tu as déclaré le propriétés IBOutlet, pour les composants de la cellule, dans le fichier .h - c'est pas conseillé. Par contre, tu devrais le mettre dans une extension de la classe dans le fichier .m - vois mon exemple.


     


    En cachant les propriétés dans le fichier .m, tu ne pourras pas y accéder en dehors de la classe cellule, du coup, il faut ajouter une propriété dans le fichier .h afin que tu puisses passer l'objet qui contient les données d'un contact.


     


    2ème question - pourquoi utilises-tu un dictionnaire pour les données ? Pourquoi pas une classe ? C'est plus fiable d'utiliser les classes parce que ça évite les problèmes de mauvaise orthographe dans les noms des propriétés. Mais tu pourrais, quand même, passer un dictionnaire au lieu d'une instance d'une classe spécifique.


     


    Que tu utilises une classe, ou un dictionnaire, tu peux, quand même, mettre tous le code pour initialiser les boutons et libelles dans la méthode - setContact - c'est plus "propre"  ;)


     


    Je t'envoie le projet par MP pour que tu puisses voir comment ça marche. Si tu as des questions, n'hésite pas à  les poser ; de préférence ici afin que les autres debutants puissent apprendre.


  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2014 modifié #23

    Si tu préfères utiliser un dictionnaire pour les données, le code ressemblerait à  ça :



    - (void)setContact:(NSDictionary *)contact
    {
    _contact = contact;

    NSString *valeur = _contact[@telephoneFixe];

    BOOL permis = [valeur length];

    if (permis)
    {
    [self.boutonTelephoneFixe setTitle:valeur forState:UIControlStateNormal];
    }
    else
    {
    [self.boutonTelephoneFixe setTitle:@- forState:UIControlStateNormal];
    }

    valeur = _contact[@telephonePortable];

    permis = [valeur length];

    self.boutonTelephonePortable.enabled = permis;

    if (permis)
    {
    [self.boutonTelephonePortable setTitle:valeur forState:UIControlStateNormal];
    }
    else
    {
    [self.boutonTelephonePortable setTitle:@- forState:UIControlStateNormal];
    }
    }

    ...

    - (void)boutonFixeTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact[@telephoneFixe]];
    }

    - (void)boutonPortableTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact[@telephonePortable]];
    }


  •  


    Si tu préférais utiliser un dictionnaire pour les données, le code semblerait :



    - (void)setContact:(NSDictionary *)contact
    {
    _contact = contact;

    NSString *valeur = _contact[@telephoneFixe];

    BOOL permis = [valeur length];

    if (permis)
    {
    [self.boutonTelephoneFixe setTitle:valeur forState:UIControlStateNormal];
    }
    else
    {
    [self.boutonTelephoneFixe setTitle:@- forState:UIControlStateNormal];
    }

    valeur = _contact[@telephonePortable];

    permis = [valeur length];

    self.boutonTelephonePortable.enabled = permis;

    if (permis)
    {
    [self.boutonTelephonePortable setTitle:valeur forState:UIControlStateNormal];
    }
    else
    {
    [self.boutonTelephonePortable setTitle:@- forState:UIControlStateNormal];
    }
    }

    ...

    - (void)boutonFixeTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact[@telephoneFixe]];
    }

    - (void)boutonPortableTouchUpInside:(UIButton *)sender
    {
    [self composerNumeroPhone:self.contact[@telephonePortable]];
    }



     


    Et du coup ma classe Contact se présenterais sous quelle forme ?

  • Joanna CarterJoanna Carter Membre, Modérateur

    Et du coup ma classe Contact se présenterais sous quelle forme ?




    Peux-tu m'expliquer ce que tu veux dire ?


  • Et du coup ma classe Contact se présenterais sous quelle forme ?




     


    NSDictionary ! 



  • Peux-tu m'expliquer ce que tu veux dire ?




     


    Sans dictionnaire elle se présente comme cela:



    @property (nonatomic) NSUInteger ID;
    @property (copy, nonatomic) NSString* nomPrenom;
    @property (copy, nonatomic) NSString* telFixe;
    @property (copy, nonatomic) NSString* telPortable;
    @property (copy, nonatomic) NSString* adMail;

    Avec dictionnaire ça ressemblerait à  quoi s'il te plait ?



  • Avec dictionnaire ça ressemblerait à  quoi s'il te plait ?




     


    @property (nonatomic, strong) NSDictionary *contact;

  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2014 modifié #29


    Sans dictionnaire elle se présente comme cela:



    @property (nonatomic) NSUInteger ID;
    @property (copy, nonatomic) NSString* nomPrenom;
    @property (copy, nonatomic) NSString* telFixe;
    @property (copy, nonatomic) NSString* telPortable;
    @property (copy, nonatomic) NSString* adMail;

    Avec dictionnaire ça ressemblerait à  quoi s'il te plait ?




     


    Ce n'est pas la peine d'utiliser un dictionnaire dans la classe Contact, tu as la choix entre utiliser la classe ou le dictionnaire.


     


    Comme dit Samir, on remplacerait l'instance de la classe Contact avec une instance de la classe NSDictionary, en utilisant le même type de code que tu avais avant de demander les conseils ici.


     


    Je me demandais, comment "ramasses-tu" les données des contacts ? En fonction de ta réponse je pourrais te dire s'il vaut mieux utiliser la classe Contact ou un dictionnaire.


  • Comment je ramasse les données de contacts ?


     


    Je les récupère dans une base de données grâce à  un webservice ;)


  • Joanna CarterJoanna Carter Membre, Modérateur

    Qu'est-ce que tu utilises comme base de données ?


Connectez-vous ou Inscrivez-vous pour répondre.