9 jan, 2009
Article abordant:
Apple, Cocoa Touch, Developpement, iPhone
Il y a peu, j’exposais ma solution pour Créer une UITableViewCell personnalisée à partir d’Interface Builder. Suite au commentaire de Bruno Da Silva, je vous laisse une version complètement fonctionnelle de l’implémentation de cette méthode.
Il s’agit d’une TableView qui va chercher les dernières photos Flickr avec pour tag « xmas ». Pourquoi donner un exemple aussi compliqué ? Tout simplement parce que je n’ai vraiment pas le temps de faire un exemple complet en ce moment et je voulais publier un exemple rapidement. J’ai donc récupéré rapidement un exemple de code que j’ai fais en interne pour le boulot.
La partie de code qui va chercher les images sur FlickR n’est pas de moi. L’auteur n’ayant pas laissé d’informations le concernant dans le code, je ne pourrais plus vous dire qui c’est (et ça me désole vraiment).
Voici l’archive contenant le projet Xcode complet (toute l’intelligence concernant la méthode pour l’UITableViewCell se trouve dans MyTableViewController.m à la méthode - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath): télécharger MyTableViewDemo.zip.
5 jan, 2009
Pro abordant:
Apple, Cocoa Touch, Developpement, iPhone
Prenons un cas simple: on a une UIView qui contient une simple UITableView (avec le UITableViewController qui va bien) ainsi qu’une UIToolBar en bas. On se retrouve avec un léger problème: la UITableView ne se redimensionne pas automatiquement en hauteur. Ainsi, les derniers éléments se retrouvent « cachés » par la barre. Voici un exemple fait à la va-vite avec Interface Builder (la UIToolBar a été volontairement mise en transparence pour illustrer le problème):

Le souci, c’est qu’il n’est pas possible de préciser dans le code la taille d’une UITableView. Après avoir essayé plusieurs solutions (dont certaines était plutôt farfelue), j’en ai retenu une. C’est celle qui m’a semblé la plus propre, simple et efficace.
La suite du billet, c’est par là »
26 déc, 2008
Pro abordant:
Apple, Cocoa Touch, Developpement, iPhone
Le problème
La TableView est un composant essentiel de l’HIM de l’iPhone très simple à développer pour des besoins simples. Clairement, si on doit afficher à l’utilisateur des cellules avec une seule ligne de texte, ça se fait les doigts dans le nez.
Là où les choses se corsent, c’est quand il faut créer des cellules personnalisées. Avec, par exemple, deux UILabel et une UIImageView. En effet, il n’existe pas de méthode pour charger un nib (comme l’habituel initWithNibName:). Ainsi, on se retrouve forcé à créer tout nos éléments et à les placer à la main dans le code. C’est loin d’être quelque chose d’agréable, simple et rapide à faire. Sans compter qu’au moindre changement de design de la cellule, on perd un temps fou.
La solution
Non, l’idéal c’est de pouvoir utiliser Interface Builder pour construire ses cellules… Après quelques essais, recherches et erreurs, voici la solution que j’ai trouvé (et que j’utilise):
La suite du billet, c’est par là »
20 déc, 2008
Pro abordant:
Apple, Cocoa Touch, Developpement, iPhone
Il y a peu, je parlais de la sérialisation d’un contact dans l’AddressBook de l’iPhone. Toujours dans la même veine, voyons comment afficher, dans une application, la photographie d’un contact de l’AddressBook.
L’idée est de partir du ABRecordRef correspondant au contact dont on souhaite afficher l’image. A partir de là, on vérifie que ce contact dispose bien d’une photo dans sa fiche (via ABPersonHasImageData(). Pour finir, on récupère les données brutes de l’image ( ABPersonCopyImageData()) et on crée la UIImage qui va bien (via initWithData:).
Au final, voilà ce que ça donne:
if(ABPersonHasImageData(recordRef))
{
NSData *myAvatarData = (NSData *) ABPersonCopyImageData(recordRef);
UIImage *avatarImage = [[UIImage alloc] initWithData:myAvatarData];
[myAvatarData release];
}
Après, il ne faut pas oublier de libérer myAvatarData puisqu’il est devenu inutile. Charge à vous ensuite d’afficher avatarImage dans le UIImageView qui va bien. Simple non ?
15 déc, 2008
Pro abordant:
Apple, Cocoa Touch, Developpement, iPhone
Dans la série des billets concernant le développement sur iPhone, en voici un nouveau qui reste dans la veine du précédent (« Récupérer une adresse email dans le AddressBook de l’iPhone »).
L’idée ce coup là, c’est de récupérer un identifiant d’un contact. Je m’explique: dans l’application que je développe je dois enregistrer (sur un serveur distant) des informations concernant un contact sélectionné par l’utilisateur. Clairement, il s’agit du nom, du prénom et de l’adresse email. Puis, dans un second temps, ces données peuvent revenir sur l’iPhone.
Seulement, il pourrait être intéressant de faire directement le lien, lors du retour de l’information, entre les personnes désignée par les données sur le serveur et l’entité qui la représente dans le AddressBook. Pourquoi ? Pour plusieurs raisons. Tout d’abord, imaginez que l’on modifie les informations concernant la personne (cas typique: on a fait une faute de frappe quand on a saisi son nom la première fois ou elle change d’adresse mail). Et bien si on est capable de détecter ce changement quand les données reviennent sur l’iPhone, on pourra répercuter les modifications sur le serveur. La seconde raison est qu’il peut être sympa de faire un lien vers la fiche de la personne dans le AddressBook quand on affiche son nom dans l’application.
Quand on arrive dans le peoplePickerNavigationController: shouldContinueAfterSelectingPerson (donc que l’utilisateur a sélectionne un contact), on ne dispose que d’un objet de type ABRecordRef. Ce type d’objet est difficilement « sérialisable » … Comprenez par là qu’il serait difficile de le transformer en une chaine de caractère et de refaire l’opération inverse (pour le « dé-sérialiser »).
La solution est d’utiliser ABRecordGetRecordID() qui retourne un identifiant unique du contact dans l’ AddressBook. Cette fonction renvoie un objet de type ABRecordID (qui n’est ni plus ni moins qu’un entier !). Au final, pour la convertir en chaine de caractère ça donne (mPerson étant notre objet de type ABRecordRef):
NSString contactId = [NSString stringWithFormat:@"%u", ABRecordGetRecordID(mPerson)];
Ensuite, l’opération inverse (récupérer le ABRecordRef a partir du de la chaine de caractère), c’est simple:
ABRecordRef recordRef = ABAddressBookGetPersonWithRecordID(addressBook, [contactId intValue]);
Notez que dans le cas où le contact n’existe pas (plus), ABAddressBookGetPersonWithRecordID() renvoie NULLVoilà, maintenant on peut effectuer n’importe quelle opération comme si on venait de récupérer le contact à partir du peoplePickerNavigationController.
21 août, 2008
Pro abordant:
Apple, Cocoa Touch, Developpement, iPhone
J’avais dit que je parlerais ici même des petites astuces ou gros problèmes rencontrés lors du développement de mon application iPhone. L’objectif est assez clair : faire gagner quelques précieuses heures aux prochains qui rencontreront les mêmes problèmes que moi. Le premier cas concret concerne le carnet d’adresse de l’iPhone.
L’idée est d’aller récupérer les informations concernant un contact que l’utilisateur aura désigné dans son carnet d’adresse. Je ne vais pas expliquer ici comment mettre en place l’interface de sélection d’un contact (le peoplePickerNavigationController). En effet, Mickaël Morvan le fait très bien dans son article sur développez : « iPhone SDK: Accès au carnet d’adresses de l’iPhone ».
Comme vous avez pu le voir, récupérer le nom et le prénom d’un contact sous forme de chaine de caractère est assez simple. Par contre, si on applique la même technique à l’adresse email (en utilisant kABPersonEmailProperty à la place de kABPersonLastNameProperty), on lève une exception Terminating_Due_To_Uncaught_Exception …
Pourquoi donc ? La première chose à comprendre c’est qu’un contact n’a qu’un seul nom. Mais il peut avoir plusieurs adresses email… Par conséquent, un ABRecordCopyValue(mPerson, kABPersonEmailProperty) ne renverra pas une seule valeur mais une collection de valeurs ! Alors, évidement, quand on veut mettre ça dans un NSString ça ne passe pas.
Pour faire simple, on va considérer que seule la première adresse email nous intéresse (généralement c’est la principale). Ce qui revient à vouloir prendre la valeur à l’index 0 de la collection de valeurs. Ensuite, et bien on caste en string. Concrètement, voilà ce que ça donne :
NSString contactMail = (NSString *)ABMultiValueCopyValueAtIndex(ABRecordCopyValue(mPerson, kABPersonEmailProperty), 0);
Après, il n’est pas dur de compléter en permettant de choisir une adresse email particulière (voir dans la littérature Apple du coté de ABMultiValue).
Mine de rien, le problème a l’air tout simple, mais il a fallu quelques heures pour en arriver là. Sans compter que toutes les recherches faites sont tombées sur des gens posant la question et n’ayant pas de réponse !
