Affichage du nom des contacts avec adressbook

J889J889 Membre
mai 2016 modifié dans API UIKit #1
Bonjour à  tous,


J' ai essayer de faire cette exemple donné sur la doc du développement :
https://developer.apple.com/library/ios/documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/QuickStart.htm


car je voudrais mettre cette fonction dans mon app.


Mais déjà  j' ai plein de warning et lorsque je teste l' app sur mon iPhone, j' accède bien à  tous les contacts après avoir cliqué sur le bouton mais lorsque je choisis une personne j' arrive à  la fiche complète de la personne. Lorsque je clique sur son portable, je lui téléphone au lieu que son nom et son numéro de tel s' inscrivent dans les labels comme indiqué dans la doc.


Quelque' un pourrait-il m' aider ?


Merci.
«13

Réponses

  • LarmeLarme Membre
    mai 2016 modifié #2

    Lis-tu les warnings ?


    AddressBook est deprecated. On est passé à  Contacts.framework maintenant.


    Ce sample app commence à  dater.


     


    Et certaines méthodes liées aux UIViewControllers sont deprecated depuis iOS6.


    N'hésite pas à  voir leur doc associée pour connaà®tre les nouvelles méthodes à  appeler.


     


    En bref, jusqu'à  maintenant


    iOS 1 => iOS8 : AddressBook.framework


    iOS9+ : Contacts.framework


     


    AddressBook est encore autorisé (pour laisser le temps aux développeurs de faire la transition), mais sera prochainement supprimé.


  • J889J889 Membre

    Oui. J' étais en train de changer les méthodes pour les remplacer par celles utilisées par Contacts.framework mais qu' est ce qui correspond à  peoplePickerDelegate ?



    picker.peoplePickerDelegate = self;

    C' est pas super de la part de Apple de laisser des anciens codes sur leur site officiel...


  • J889J889 Membre

    En plus même si je choisi la cible du déploiement à  iOS 8 il y a toujours le problème du code qui ne correspond pas à  ce qu' ils indiquent.


  • J889J889 Membre

    J' ai remplacé tous les warning. Plus aucun warning mais le code ne fais pas ce qu' ils disent. Lorsque je clique sur un contact, on arrive sur le détail de celui-ci au lieu de retourner sur la vue et avec le nom de la personne et le numéro de tel inscrit dans leur label respectifs.


  • DrakenDraken Membre
    mai 2016 modifié #7


    C' est pas super de la part de Apple de laisser des anciens codes sur leur site officiel...




    C'est des spécialistes de la chose .. Il faudrait effacer des pans entiers du site pour le mettre à  jour.


  • Joanna CarterJoanna Carter Membre, Modérateur
    Pour que CNContactPickerViewController renvoie le contact, il faut fournir un NSPredicate(true) pour la var predicateForSelectionOfContact. Sinon, la fiche du contact se présentera.
  • CéroceCéroce Membre, Modérateur

    C' est pas super de la part de Apple de laisser des anciens codes sur leur site officiel...


    Il arrive qu'on doive maintenir du vieux code. Si, si. Et on est bien content de trouver quelque information que ce soit.
  • J889J889 Membre

    Merci à  vous pour vos réponses.


    Avant d' aller voir du côté de Contact.framework je reste encore avec AdressBook.framework et je ne comprends pas pourquoi mon code ne fonctionne pas et lance la fiche du carnet d' adresse quand on clique sur un contact.



    #import "ViewControllerContacts.h"

    @interface ViewControllerContacts ()

    @end

    @implementation ViewControllerContacts

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    }

    - (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

    /*
    #pragma mark - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
    }
    */

    - (IBAction)showPicker:(id)sender {

    //CNContactPickerViewController *picker =
    //[[CNContactPickerViewController alloc] init];

    ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
    picker.peoplePickerDelegate = self;


    [self presentViewController:picker animated:YES completion:nil];

    }






    - (BOOL)peoplePickerNavigationController:
    (ABPeoplePickerNavigationController *)peoplePicker
    shouldContinueAfterSelectingPerson:(ABRecordRef)person {

    [self displayPerson:person];
    //[self dismissModalViewControllerAnimated:YES];
    [self dismissViewControllerAnimated:YES completion:nil];

    return NO;
    }



    - (BOOL)peoplePickerNavigationController:
    (ABPeoplePickerNavigationController *)peoplePicker
    shouldContinueAfterSelectingPerson:(ABRecordRef)person
    property:(ABPropertyID)property
    identifier:(ABMultiValueIdentifier)identifier
    {
    return NO;
    }

    - (void)displayPerson:(ABRecordRef)person
    {
    NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person,
    kABPersonFirstNameProperty);
    self.firstName.text = name;

    NSString* phone = nil;
    ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,
    kABPersonPhoneProperty);
    if (ABMultiValueGetCount(phoneNumbers) > 0) {
    phone = (__bridge_transfer NSString*)
    ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
    } else {
    phone = @[None];
    }
    self.phoneNumber.text = phone;
    CFRelease(phoneNumbers);

    }

    Si vraiment c' est pas possible de le faire marcher j' irai voir du côté de Contact.framework mais déjà  que tous les exemples sur internet sont en swift.

    Tout le monde c' est mis au swift ici ?


  • J889J889 Membre

    Joanna, tu me donnes la correction pour le Contact.framework. C' est le même chose pour le Adressbook.framework ?


  • Joanna CarterJoanna Carter Membre, Modérateur

    De ce que je peux voir dans les docs, oui.


  • LarmeLarme Membre

    Il va falloir être plus explicite.


    Qu'est-ce qui ne marche pas concrètement ?


    "je ne comprends pas pourquoi mon code ne fonctionne pas et lance la fiche du carnet d' adresse quand on clique sur un contact."


    Absolument pas compris avec la négation au départ et le reste, c'est ce que tu voudrais ?


     


    Quel est le code appelé ? As-tu mis des breakpoints ? Des NSLog() au moins ?


    Peux-tu ne pas indiquer les codes inutiles où tu appelles juste les super : didReceiveMemoryWarning, viewDidLoad, le code commenté de prepareForSegue:sender: ?


     


    De la clarté, et pointer le problème exactement nous facilite la tâche et nous donne plus envie de te répondre. Et oui, ne pas oublier la présentation et la communication est aussi un gros soucis chez des développeurs indépendants (le Marketing, ce n'est pas pour rien !)



     


  • J889J889 Membre

    Oui, c' est vrai, je vais être plus clair.


    J' ai mis des breakpoint mais rien n' est anormal lors de l' interprétation de code. Aucun warning non plus. Je n' ai pas mis de NSlog parce que je ne sais pas comment bien m' en servir à  part si c' est pour faire un truc du style vérifier qu' un texte s' affiche bien dans un UILabel.


     


    Le problème est que dans la doc de Apple, il est stipulé qu' après avoir cliqué sur le UIBouton "showPicker" :


     


    1 - Le carnet d' adresse se lance


    2 - On appuie sur le nom d' un contact


    3 - Il en résulte la fermeture du carnet d' adresse


    4 - Le nom et le numéro de tel s' affichent dans les UILabel correspondants


    Moi, lorsque j' inscris le code donné, il se passe ceci après avoir cliqué sur le UIBouton "showPicker" :


    1 - Le carnet d' adresse se lance


    2 - On appuie sur le nom d' un contact


    3 - On arrive sur la vue du contact avec son numéro de tel, son email, son adresse, etc (toujours dans le carnet d' adresse)


    4 - On est obligé de faire cancel pour revenir à  la vue de l' app. Les UILabel affichent toujours le texte inscrit dans le Main.storyboard


     


    La doc dit aussi qu' en arrivant sur la vue (avant de cliquer sur le UIBouton "showPicker") les UILabel sont vide de texte alors que moi ils sont remplis avec le texte que j' ai écris que le Main.storyboard.


    J' espère que c' est un peu plus clair :-)


     


    Je remets le code du .m



    - (IBAction)showPicker:(id)sender {

    ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
    picker.peoplePickerDelegate = self;

    [self presentViewController:picker animated:YES completion:nil];

    }

    - (BOOL)peoplePickerNavigationController:
    (ABPeoplePickerNavigationController *)peoplePicker
    shouldContinueAfterSelectingPerson:(ABRecordRef)person {

    [self displayPerson:person];
    [self dismissViewControllerAnimated:YES completion:nil];

    return NO;
    }

    - (BOOL)peoplePickerNavigationController:
    (ABPeoplePickerNavigationController *)peoplePicker
    shouldContinueAfterSelectingPerson:(ABRecordRef)person
    property:(ABPropertyID)property
    identifier:(ABMultiValueIdentifier)identifier
    {
    return NO;
    }

    - (void)displayPerson:(ABRecordRef)person
    {
    NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person,
    kABPersonFirstNameProperty);
    self.firstName.text = name;

    NSString* phone = nil;
    ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,
    kABPersonPhoneProperty);
    if (ABMultiValueGetCount(phoneNumbers) > 0) {
    phone = (__bridge_transfer NSString*)
    ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
    } else {
    phone = @[None];
    }
    self.phoneNumber.text = phone;
    CFRelease(phoneNumbers);

    }

    Maintenant je vais aller voir du côté de NSPredicate(true) comme Joanna me l' a dit.


    Je vais voir si c' est la même syntaxe et méthode utilisé avec AdressBook.framework.



     


  • J889J889 Membre

    Joanna, tu as des exemples de doc ou tu as vu qu' il faut mettre NSPredicate(true) pour la var predicateForSelectionOfContact ?


    Il faut le mettre où ?


  • LarmeLarme Membre

    Je n'ai jamais utilisé AdressBook, mais en lisant le nom des méthodes, je suppose qu'en sélectionnant une personne l'une des deux méthodes suivant devrait être appelée :



    ​- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person

    - (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier

    Laquelle des deux est appelée ?


    Tu retournes NO dans les deux cas, mais tu ne lis les infos que dans l'une des deux.


  • J889J889 Membre

    Comment ça laquelle des deux ? Les deux.


    Je me demande si je dois pas trouver un autre moyen de faire apparaitre le numéro de tel d' un contact dans UILabel.


    Le code qui répond est celui qui lance le carnet d' adresse après avoir appuyer sur le bouton. A part ça c' est comme si il n' y avait pas de code.


  • LarmeLarme Membre

    Bah, dans l'un d'une part tu fais un dismiss, donc normalement, le controller devrait dégager.

    Ensuite, tu récupère aussi l'objet person, donc est-ce que cet variable est valide, et ça devrait appeler displayPerson:, est-ce le cas ? Si tu regardes les valeurs, ça semble être bon ? Les IBOutlet sont nil?


  • J889J889 Membre

    En théorie il devrait dégager mais il dégage pas.


    Comment faire pour voir si la variable est valide. En théorie elle l' est. D' après le code elle appelle displayPerson.


    Dans la console de début rien ne s' inscrit.

  • J889J889 Membre

    Personne pour m' aider ?


  • Joanna CarterJoanna Carter Membre, Modérateur
    mai 2016 modifié #21

    Pour utiliser Contacts :



    class ViewController: UIViewController, CNContactPickerDelegate
    {
    var contactPicker: CNContactPickerViewController?

    @IBOutlet weak var textField: UITextField!

    @IBAction func showPicker()
    {
    contactPicker = CNContactPickerViewController()

    contactPicker?.predicateForSelectionOfContact = NSPredicate(value: true)

    contactPicker?.delegate = self

    presentViewController(contactPicker!, animated: true)
    {

    }
    }

    func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact)
    {
    textField.text = "\(contact.givenName) \(contact.familyName)"

    dismissViewControllerAnimated(true)
    {
    self.contactPicker = nil
    }
    }
    }

    Et presque le même code pour AddressBook :



    class ViewController: UIViewController, ABPeoplePickerNavigationControllerDelegate
    {
    var contactPicker: ABPeoplePickerNavigationController?

    @IBOutlet weak var textField: UITextField!

    @IBAction func showPicker()
    {
    contactPicker = ABPeoplePickerNavigationController()

    contactPicker?.predicateForSelectionOfPerson = NSPredicate(value: true)

    contactPicker?.peoplePickerDelegate = self

    presentViewController(contactPicker!, animated: true)
    {

    }
    }

    func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord)
    {
    let firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as! String

    let lastName = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as! String

    textField.text = "\(firstName) \(lastName)"

    dismissViewControllerAnimated(true)
    {
    self.contactPicker = nil
    }
    }
    }

    Mais avec pas mal de warnings  ::)


  • Joanna CarterJoanna Carter Membre, Modérateur
    mai 2016 modifié #22

    Ou, si tu insistes à  utiliser Objective-C  ???



    @import Contacts;
    @import ContactsUI;


    @interface ViewController () <CNContactPickerDelegate>

    @property (strong, nonatomic) CNContactPickerViewController *contactPicker;

    @property (weak, nonatomic) IBOutlet UITextField *textField;

    - (IBAction)showPicker;

    @end


    @implementation ViewController

    - (void)showPicker
    {
    self.contactPicker = [[CNContactPickerViewController alloc] init];

    self.contactPicker.predicateForSelectionOfContact = [NSPredicate predicateWithValue:YES];

    self.contactPicker.delegate = self;

    [self presentViewController:self.contactPicker animated:YES completion:^
    {

    }];
    }

    - (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact
    {
    self.textField.text = [NSString stringWithFormat:@%@ %@", contact.givenName, contact.familyName];

    [self dismissViewControllerAnimated:YES completion:^
    {
    self.contactPicker = nil;
    }];
    }

    @end


    @import AddressBook;
    @import AddressBookUI;


    @interface ViewController () <ABPeoplePickerNavigationControllerDelegate>

    @property (strong, nonatomic) ABPeoplePickerNavigationController *contactPicker;

    @property (weak, nonatomic) IBOutlet UITextField *textField;

    - (IBAction)showPicker;

    @end


    @implementation ViewController

    - (void)showPicker
    {
    self.contactPicker = [[ABPeoplePickerNavigationController alloc] init];

    self.contactPicker.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:YES];

    self.contactPicker.peoplePickerDelegate = self;

    [self presentViewController:self.contactPicker animated:YES completion:^
    {

    }];
    }

    - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person
    {
    NSString* firstName = (__bridge_transfer NSString*)ABRecordCopyValue(person,
    kABPersonFirstNameProperty);
    NSString* lastName = (__bridge_transfer NSString*)ABRecordCopyValue(person,
    kABPersonLastNameProperty);

    self.textField.text = [NSString stringWithFormat:@%@ %@", firstName, lastName];

    [self dismissViewControllerAnimated:YES completion:^
    {
    self.contactPicker = nil;
    }];
    }

    @end

  • J889J889 Membre

    Merci Joanna.

    Oui, j' utilise l' Objective C car je me remet au app iPhone après un long moment. Je dois me mettre au swift. Et déjà  que j' ai des lacune sen objective c... Tout le monde programme en swift ici ou bien il y a encore des irréductible de l' obj c ?


     


    J' essaie de passer le numéro du contact choisi avec la même méthode que le dernier code que tu as envoyé :



    NSString* phoneNumber = (__bridge_transfer NSString*)ABRecordCopyValue(person,
    kABPersonPhoneProperty);

    self.textFieldPhone.text = [NSString stringWithFormat:@%@", phoneNumber];

    mais j' ai des erreurs. Comment fait-on pour spécifier que c' est un numéro de tel ou des chiffres ?


  • J889J889 Membre

    self.textFieldPhone.text = [NSString stringWithFormat:@%d, phoneNumber];

    n' est pas bon. J' ai une suite qui s' inscrit à  la place du numéro de téléphone.


  • J889J889 Membre

    En fait après avoir choisit un contact à  appeler, j' ai un message dans le textField qui doit contenir le numéro de tel : ABMultiValueRef 0x12e538e


     


    J' ai remis :



    self.textFieldPhone.text = [NSString stringWithFormat:@"", phoneNumber];


    parce que je pense que ça n' a rien à  voir.


  • Joanna CarterJoanna Carter Membre, Modérateur
    mai 2016 modifié #26
    Si tu avais lu les docs tu aurais vu que kABPersonPhoneProperty renvoie (effectivement) un array de numeros de téléphone.
  • J889J889 Membre

    Même en la lisant ce n' est pas toujours évidant lorsqu' on apprend seul...

    ça fait un moment que je cherche...

     



    NSArray* phoneNumber = (__bridge_transfer NSArray*)ABRecordCopyValue(person,
    kABPersonPhoneProperty);

    self.textFieldPhone.text = [NSArray arrayWithObjects:(phoneNumber,nil)];

    Le code ne fonctionne pas.


  • Plutôt


    Self.textFieldPhone.text = [phoneNumber firstObject]
  • J889J889 Membre
    mai 2016 modifié #29

    Toujours pas...

    L' app bloque...


  • Joanna CarterJoanna Carter Membre, Modérateur
    mai 2016 modifié #30

    J'ai dit "effectivement" mais c'est pas la meilleure traduction de ce que je pensais.


     


    Oui, c'est une liste mais c'est, en réalité, un ABMultiValueRef.



    - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person
    {
    ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);

    for(CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++)
    {
    CFStringRef label = ABMultiValueCopyLabelAtIndex(phoneNumbers, i);

    if (CFStringCompare(label, kABPersonPhoneMobileLabel, 0))
    {
    self.textField.text = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneNumbers, i);
    }

    CFRelease(label);
    }

    CFRelease(phoneNumbers);

    [self dismissViewControllerAnimated:YES completion:^
    {
    self.contactPicker = nil;
    }];
    }

    C'est un sacré boulot d'utiliser ABAddressBook, avec tous les types CF..., qu'il faut relâcher tous le temps.


     


    Même si tu tiens à  Objective-C, je te conseillerais fortement à  utiliser le Contacts Framework, c'est beaucoup plus facile.



    - (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact
    {
    NSArray<CNLabeledValue<CNPhoneNumber *> *> *phoneNumbers = contact.phoneNumbers;

    for (CNLabeledValue<CNPhoneNumber *> *labeledValue in phoneNumbers)
    {
    if ([labeledValue.label isEqualToString:CNLabelPhoneNumberMobile])
    {
    self.textField.text = labeledValue.value.stringValue;
    ​ }
    }

    [self dismissViewControllerAnimated:YES completion:^
    {
    self.contactPicker = nil;
    }];
    }
  • J889J889 Membre

    D' accord. ça marche. Merci à  vous et surtout à  Joanna.


    C' est vrai que c pas évident. En plus si on choisit un contact qui n' a pas enregistré le numéro de tel dans la case portable, il n' y a rien qui s' affiche et du coup si on a choisit un autre contact juste avant (qui lui a enregistré un numéro de tel dans la case portable) c' est son numéro de tel portable qui reste affiché dans le textField.


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