<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Webd &#187; Cocoa Touch</title>
	<atom:link href="http://webd.fr/tag/cocoa-touch/feed" rel="self" type="application/rss+xml" />
	<link>http://webd.fr</link>
	<description>Le blog de Julien Quéré</description>
	<lastBuildDate>Wed, 08 Sep 2010 16:39:53 +0000</lastBuildDate>
	<language>fr</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Nib2objc: Ou comment convertir un nib en code Objectif-C</title>
		<link>http://webd.fr/735-nib2objc-ou-comment-convertir-un-nib-en-code-objectif-c</link>
		<comments>http://webd.fr/735-nib2objc-ou-comment-convertir-un-nib-en-code-objectif-c#comments</comments>
		<pubDate>Wed, 10 Jun 2009 14:49:40 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=735</guid>
		<description><![CDATA[L&#8217;utilisation d&#8217;Interface Builder s&#8217;avère très pratique pour les développeurs Cocoa Touch. C&#8217;est vrais que c&#8217;est génial de pouvoir créer ses interfaces en mode WYSIWYG. Oui mais voilà, cela peut poser quelques problèmes. Outre les cas où l&#8217;utilisation du code est nécessaire (pour atteindre la granularité voulue), on peut vouloir renoncer à l&#8217;utilisation des nibs pour [...]]]></description>
			<content:encoded><![CDATA[<p>L&#8217;utilisation d&#8217;Interface Builder s&#8217;avère très pratique pour les développeurs Cocoa Touch. C&#8217;est vrais que c&#8217;est génial de pouvoir créer ses interfaces en mode WYSIWYG. Oui mais voilà, cela peut poser quelques problèmes. Outre les cas où l&#8217;utilisation du code est nécessaire (pour atteindre la granularité voulue), on peut vouloir renoncer à l&#8217;utilisation des nibs pour des raisons de performance. </p>
<p>En effet, dans certains cas l&#8217;utilisation des nibs pose de sérieux problèmes de performance. On se retrouve ainsi avec un dur choix: soit on choisit la simplicité (et on utilise Interface Builder), soit on écrit ses interfaces directement dans le code et on gagne en performance. Dans certains cas, l&#8217;impact de l&#8217;utilisation des nibs sur la performance est quasi nul. La question ne se pose donc pas. Mais parfois, ce n&#8217;est pas le cas.<br />
<span id="more-735"></span><br />
Dans ce dernier cas de figure, il existe maintenant une solution: nib2objc. Ce projet Open-Source  est tout simplement un convertisseur de fichiers nib (.xib) vers du code Objectif-C. Il gère toutes les propriétés publiques de chacun des éléments graphiques, le constructeur et la hiérarchie des vues. Pour le moment, il n&#8217;y a que les composants d&#8217;UIKit qui sont supportés. L&#8217;utilisation est on-ne-peut-plus simple: </p>
<pre lang="">imac-de-julien-2:Debug julien$ ./nib2objc demo.xib > demo.m</pre>
<p><a href="http://webd.fr/wp-content/uploads/2009/06/image-6.png" rel="lightbox[735]" title="image-6"><img src="http://webd.fr/wp-content/uploads/2009/06/image-6-300x224.png" alt="image-6" title="image-6" width="300" height="224" class="aligncenter size-medium wp-image-738" /></a></p>
<p>Et voilà le résultat pour ce nib:</p>
<pre lang="objc">
UILabel *view6 = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 20.0, 260.0, 21.0)];
view6.frame = CGRectMake(20.0, 20.0, 260.0, 21.0);
view6.adjustsFontSizeToFitWidth = YES;
view6.alpha = 1.000;
view6.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
view6.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
view6.clearsContextBeforeDrawing = YES;
view6.clipsToBounds = YES;
view6.contentMode = UIViewContentModeScaleToFill;
view6.enabled = YES;
view6.font = [UIFont fontWithName:@"Helvetica" size:17.000];
view6.hidden = NO;
view6.lineBreakMode = UILineBreakModeTailTruncation;
view6.minimumFontSize = 10.000;
view6.multipleTouchEnabled = NO;
view6.numberOfLines = 1;
view6.opaque = NO;
view6.shadowOffset = CGSizeMake(0.0, -1.0);
view6.tag = 0;
view6.text = @"Ma célule personalisée";
view6.textAlignment = UITextAlignmentCenter;
view6.textColor = [UIColor colorWithRed:0.000 green:0.000 blue:0.000 alpha:1.000];
view6.userInteractionEnabled = NO;

UITableViewCell *view4 = [[UITableViewCell alloc] initWithFrame:CGRectMake(0.0, 0.0, 300.0, 182.0) reuseIdentifier:(null)];
view4.frame = CGRectMake(0.0, 0.0, 300.0, 182.0);
view4.accessoryType = UITableViewCellAccessoryNone;
view4.alpha = 1.000;
view4.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
view4.backgroundColor = [UIColor colorWithRed:1.000 green:1.000 blue:1.000 alpha:1.000];
view4.clearsContextBeforeDrawing = NO;
view4.clipsToBounds = NO;
view4.contentMode = UIViewContentModeScaleToFill;
view4.font = [UIFont fontWithName:@"Helvetica" size:17.000];
view4.hidden = NO;
view4.hidesAccessoryWhenEditing = YES;
view4.indentationLevel = 0;
view4.indentationWidth = 10.000;
view4.lineBreakMode = UILineBreakModeTailTruncation;
view4.multipleTouchEnabled = NO;
view4.opaque = YES;
view4.selectedTextColor = [UIColor colorWithWhite:1.000 alpha:1.000];
view4.selectionStyle = UITableViewCellSelectionStyleBlue;
view4.showsReorderControl = NO;
view4.tag = 0;
view4.textAlignment = UITextAlignmentLeft;
view4.textColor = [UIColor colorWithWhite:0.000 alpha:1.000];
view4.userInteractionEnabled = YES;

UIButton *view7 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
view7.frame = CGRectMake(101.0, 49.0, 99.0, 37.0);
view7.adjustsImageWhenDisabled = YES;
view7.adjustsImageWhenHighlighted = YES;
view7.alpha = 1.000;
view7.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
view7.clearsContextBeforeDrawing = NO;
view7.clipsToBounds = NO;
view7.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
view7.contentMode = UIViewContentModeScaleToFill;
view7.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
view7.enabled = YES;
view7.font = [UIFont fontWithName:@"Helvetica-Bold" size:15.000];
view7.hidden = NO;
view7.highlighted = NO;
view7.multipleTouchEnabled = NO;
view7.opaque = NO;
view7.reversesTitleShadowWhenHighlighted = NO;
view7.selected = NO;
view7.showsTouchWhenHighlighted = NO;
view7.tag = 0;
view7.titleShadowOffset = CGSizeMake(1.0, 1.0);
view7.userInteractionEnabled = YES;
[view7 setTitle:@"Un bouton" forState:UIControlStateNormal];
[view7 setTitleColor:[UIColor colorWithWhite:1.000 alpha:1.000] forState:UIControlStateHighlighted];
[view7 setTitleColor:NSPatternColorSpace NSImage 0x2c3e5a0 Size={320, 460} Reps=(
    NSBitmapImageRep 0x2c49460 Size={320, 460} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=320x460 Alpha=YES Planar=NO Format=1
) forState:UIControlStateNormal];
[view7 setTitleShadowColor:NSNamedColorSpace System controlColor forState:UIControlStateNormal];

UISwitch *view8 = [[UISwitch alloc] initWithFrame:CGRectMake(103.0, 103.0, 94.0, 27.0)];
view8.frame = CGRectMake(103.0, 103.0, 94.0, 27.0);
view8.alpha = 1.000;
view8.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
view8.clearsContextBeforeDrawing = YES;
view8.clipsToBounds = YES;
view8.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
view8.contentMode = UIViewContentModeScaleToFill;
view8.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
view8.enabled = YES;
view8.hidden = NO;
view8.highlighted = YES;
view8.multipleTouchEnabled = YES;
view8.on = YES;
view8.opaque = NO;
view8.selected = NO;
view8.tag = 0;
view8.userInteractionEnabled = YES;

[view4 addSubview:view6];
[view4 addSubview:view7];
[view4 addSubview:view8];
</pre>
<p>Comme vous pouvez le voir, c&#8217;est très verbeux. C&#8217;est parce que l&#8217;outil ne détecte pas les valeurs qui sont là par défaut. Donc dans le doute, il génère toutes les propriétés. A noter aussi que les valeurs des propriétés <code>UIImage</code>, <code>NSLocale</code> et <code>NSTimeZone</code> ne sont pas sorties dans le code. En effet, ibtool (sur lequel nib2objc se base) ne les supporte pas. </p>
<p><a href="http://kosmaczewski.net/projects/nib2objc/">Plus d&#8217;informations sur la page du projet nib2objc du site d&#8217;Adrian Kosmaczewski</a>. </p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/735-nib2objc-ou-comment-convertir-un-nib-en-code-objectif-c/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Comparer deux NSDate</title>
		<link>http://webd.fr/637-comparer-deux-nsdate</link>
		<comments>http://webd.fr/637-comparer-deux-nsdate#comments</comments>
		<pubDate>Fri, 05 Jun 2009 08:49:47 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=637</guid>
		<description><![CDATA[Il est souvent utile de comparer deux NSDate dans le temps. Il s&#8217;agit de savoir si une date est antérieure ou postérieure à une autre. Le mécanisme offert par Apple pour les comparaisons de NSDate n&#8217;est pas des plus pratiques. Il faut utiliser la méthode compare:(NSDate*)date qui retourne un objet de type NSComparisonResult. Cette méthode [...]]]></description>
			<content:encoded><![CDATA[<p>Il est souvent utile de comparer deux <code>NSDate</code> dans le temps. Il s&#8217;agit de savoir si une date est antérieure ou postérieure à une autre. Le mécanisme offert par Apple pour les comparaisons de <code>NSDate</code> n&#8217;est pas des plus pratiques. Il faut utiliser la méthode <code>compare:(NSDate*)date</code> qui retourne un objet de type <code>NSComparisonResult</code>. </p>
<p>Cette méthode est une méthode standard de Foundation. Elle permet, grâce à des résultats de comparaison standardisés d&#8217;effectuer un tri sur des objets de façon générique. Oui, mais Apple ne prévoit pas de méthodes un peu plus <i>haut niveau</i> pour les simples comparaisons de dates. Voilà pourquoi j&#8217;ai écrit rapidement une addition de la classe <code>NSDate</code> permettant de comparer deux dates intuitivement. Les voici:<br />
<span id="more-637"></span></p>
<pre lang="objc">
//
//  NSDateAdditions.h
//
//  Created by Julien on 28/05/09.
//  Copyright 2009 Julien Quéré - Webd.fr. All rights reserved.
//

#import <foundation>

@interface NSDate (NSDateAdditions)
-(BOOL) isLaterThanOrEqualTo:(NSDate*)date;
-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date;
-(BOOL) isLaterThan:(NSDate*)date;
-(BOOL) isEarlierThan:(NSDate*)date;
@end

//  NSDateAdditions.m
//
//  Created by Julien on 28/05/09.
//  Copyright 2009 Julien Quéré - Webd.fr. All rights reserved.
//

#import "NSDateAdditions.h"

@implementation NSDate (NSDateAdditions)

-(BOOL) isLaterThanOrEqualTo:(NSDate*)date {
	return !([self compare:date] == NSOrderedAscending);
}

-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date {
	return !([self compare:date] == NSOrderedDescending);
}
-(BOOL) isLaterThan:(NSDate*)date {
	return ([self compare:date] == NSOrderedDescending);

}
-(BOOL) isEarlierThan:(NSDate*)date {
	return ([self compare:date] == NSOrderedAscending);
}

@end
</pre>
<p>L&#8217;utilisation, quant à elle est on-ne-peut plus simple:</p>
<pre lang="objc">
// Compare a NSDate (maDate) and the actual date
if([maDate isEarlierThanOrEqualTo:[NSDate date]])
{
	NSLog(@"It's earlier or equal");
}
else
{
	NSLog(@"It's later");
}
</pre>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/637-comparer-deux-nsdate/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Redimensionner une UIImage</title>
		<link>http://webd.fr/320-redimensionner-une-uiimage</link>
		<comments>http://webd.fr/320-redimensionner-une-uiimage#comments</comments>
		<pubDate>Fri, 27 Feb 2009 15:14:04 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=320</guid>
		<description><![CDATA[Dans certains cas, il peut être utile de redimensionner une UIImage. En effet, même si UIImageView gère très bien le redimensionnement, on peut vouloir exporter une image dans une certaine taille. De même, il n&#8217;est pas forcement utile de stocker (en mémoire ou bien en dur) une image de grande taille si c&#8217;est pour l&#8217;afficher [...]]]></description>
			<content:encoded><![CDATA[<p>Dans certains cas, il peut être utile de redimensionner une <code>UIImage</code>. En effet, même si <code>UIImageView</code> gère très bien le redimensionnement, on peut vouloir exporter une image dans une certaine taille. De même, il n&#8217;est pas forcement utile de stocker (en mémoire ou bien en dur) une image de grande taille si c&#8217;est pour l&#8217;afficher réduite par la suite. </p>
<p>Pour redimensionner une image, c&#8217;est plutôt simple ! L&#8217;idée est de créer un contexte d&#8217;image de la taille souhaitée (ici 40*40 pixels). Dans ce contexte, en dessine l&#8217;image à redimensionner dans la taille souhaitée. Il ne reste alors plus qu&#8217;à récupérer l&#8217;image redimensionnée avec un <code>UIGraphicsGetImageFromCurrentImageContext</code>. Pour finir, on pensera bien à fermer le contexte courant. </p>
<p>Voici le code final: </p>
<pre lang="objc">
CGSize size = CGSizeMake(40, 40);
UIGraphicsBeginImageContext( size );
[avatarImage drawInRect:CGRectMake(0,0,size.width,size.height)];
avatarImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
</pre>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/320-redimensionner-une-uiimage/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Désactiver les NSLog en release</title>
		<link>http://webd.fr/307-desactiver-les-nslog-en-release</link>
		<comments>http://webd.fr/307-desactiver-les-nslog-en-release#comments</comments>
		<pubDate>Fri, 20 Feb 2009 15:28:09 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=307</guid>
		<description><![CDATA[Le NSLog est l&#8217;outil de base dans le développement et le déboguage d&#8217;application Cocoa (donc Cocoa Touch). Seulement, l&#8217;utilisation de NSLog n&#8217;est pas si anodine qu&#8217;elle peut paraître … Le fait d&#8217;envoyer une chaine de caractère à la sortie console consomme des ressources. Certes, c&#8217;est peu de choses, mais quand un NSLog est inclus dans [...]]]></description>
			<content:encoded><![CDATA[<p>Le <code>NSLog</code> est l&#8217;outil de base dans le développement et le déboguage d&#8217;application Cocoa (donc Cocoa Touch). Seulement, l&#8217;utilisation de <code>NSLog</code> n&#8217;est pas si anodine qu&#8217;elle peut paraître … Le fait d&#8217;envoyer une chaine de caractère à la sortie console consomme des ressources. </p>
<p>Certes, c&#8217;est peu de choses, mais quand un <code>NSLog</code> est inclus dans une boucle, se déclenche à chaque <code>touchesMoved:</code> (par exemple), il commence à ralentir très sérieusement le fonctionnement de l&#8217;application. Sans compter qu&#8217;une fois l&#8217;application distribuée, il est possible pour l&#8217;utilisateur final de lire ce qui se trouve dans les logs … Ce qui n&#8217;est pas forcement voulu pour le développeur. </p>
<p>L&#8217;idée serait donc, quand on est en configuration de compilation « release », de désactiver (automatiquement les <code>NSLog</code>). <span id="more-307"></span>Pour ce faire, on va simplement ajouter le code suivant dans <code>leNomDeLApplication_Prefix.pch</code> (il s&#8217;agit simplement d&#8217;un fichier qui est inclus dans tous les fichiers d&#8217;un projet):</p>
<pre lang="objc">
#ifndef DEBUG
#define NSLog //
#endif
</pre>
<p>Le code veut simplement dire: <cite>Si <code>DEBUG</code> n&#8217;est pas activé, on remplace les <code>NSLog</code> par des commentaires</cite>. On pensera donc à ajouter un flag <code>DEBUG</code> dans <code>GCC_PREPROCESSOR_DEFINITIONS</code> de la configuration de compilation dans le mode <code>Debug</code>. Notez que, par défaut, <code>GCC_PREPROCESSOR_DEFINITIONS</code> n&#8217;existe pas, il faudra donc le créer à la main. </p>
<p><a href="http://webd.fr/wp-content/uploads/2009/02/disablenslogscreen.png" rel="lightbox[307]" title="disablenslogscreen"><img src="http://webd.fr/wp-content/uploads/2009/02/disablenslogscreen-281x300.png" alt="disablenslogscreen" title="disablenslogscreen" width="281" height="300" class="aligncenter size-medium wp-image-308" /></a></p>
<p>Voilà, c&#8217;est fini <img src='http://webd.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Notez tout de même que cette façon de faire a une limitation: il faut que les <code>NSLog</code> soient définis sur une seule ligne. Mais bon, ça l&#8217;est dans 99% des cas ! </p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/307-desactiver-les-nslog-en-release/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Iphonelite3: Une nouvelle librairie SQLite pour iPhone</title>
		<link>http://webd.fr/288-iphonelite3-une-nouvelle-librairie-sqlite-pour-iphone</link>
		<comments>http://webd.fr/288-iphonelite3-une-nouvelle-librairie-sqlite-pour-iphone#comments</comments>
		<pubDate>Thu, 29 Jan 2009 20:32:18 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[SQLite]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=288</guid>
		<description><![CDATA[Je viens de découvrir aujourd&#8217;hui une nouvelle librairie permettant de simplifier l&#8217;utilisation de SQLite3 sur iPhone: Iphonelite3. L&#8217;idée global du projet est de ne pas avoir à coder une seule ligne de SQL dans son application. Il s&#8217;agit tout bêtement de faire de la persistance d&#8217;objet. Là où le concept est intéressant, c&#8217;est qu&#8217;il ne [...]]]></description>
			<content:encoded><![CDATA[<p>Je viens de découvrir aujourd&#8217;hui une nouvelle librairie permettant de simplifier l&#8217;utilisation de SQLite3 sur iPhone: Iphonelite3. L&#8217;idée global du projet est de ne pas avoir à coder une seule ligne de SQL dans son application. Il s&#8217;agit tout bêtement de faire de la persistance d&#8217;objet. Là où le concept est intéressant, c&#8217;est qu&#8217;il ne se base pas sur des objets héritant d&#8217;une quelconque implémentation de serialisation. </p>
<p>Non, l&#8217;idée est plus axée « hibernate » (que l&#8217;on trouve avec Java). Vous passez votre objet au gestionnaire de base de données et il s&#8217;occupe de tout le reste. Je ne vais pas continuer à faire l&#8217;article de Iphonelite3, son auteur le fait très bien <a href="http://iphonelite3.wordpress.com/">sur son blog dédié</a>. Notez que le projet est, pour le moment, en phase <cite>alpha</cite> et ne doit donc pas être utilisé en phase de production. Mais c&#8217;est à regarder avec attention. </p>
<p>Au passage, je rappellerais ce qui se fait sur ce segment en ce moment. Il y a les projets <a href="http://code.google.com/p/flycode/source/browse/trunk/fmdb">FMDB</a> (que j&#8217;utilise dans deux de mes projets), <a href="http://code.google.com/p/sqlitepersistentobjects/">SQLitePersistentObjects</a> (que je n&#8217;ai pas pu utiliser dans mon dernier projet car il gère mal les <code>NSMutableDictionary</code>) et <a href="http://code.google.com/p/entropydb/">EntropyDB</a>.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/288-iphonelite3-une-nouvelle-librairie-sqlite-pour-iphone/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Une UITableView triée par ordre alphabétique</title>
		<link>http://webd.fr/237-une-uitableview-triee-par-ordre-alphabetique</link>
		<comments>http://webd.fr/237-une-uitableview-triee-par-ordre-alphabetique#comments</comments>
		<pubDate>Mon, 26 Jan 2009 07:08:57 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=237</guid>
		<description><![CDATA[L&#8217;UITableView est un outil idéal pour afficher une certaine quantité de données à l&#8217;utilisateur. Seulement voilà, quand cette quantité de données devient grande, il peut être intéressant de permettre à l&#8217;utilisateur d&#8217;accéder rapidement à l&#8217;information qu&#8217;il souhaite. Une des solutions est d&#8217;utiliser le tri par ordre alphabétique. C&#8217;est l&#8217;idéal pour l&#8217;affichage de contacts (par exemple). [...]]]></description>
			<content:encoded><![CDATA[<p>L&#8217;<code>UITableView</code> est un outil idéal pour afficher une certaine quantité de données à l&#8217;utilisateur. Seulement voilà, quand cette quantité de données devient grande, il peut être intéressant de permettre à l&#8217;utilisateur d&#8217;accéder rapidement à l&#8217;information qu&#8217;il souhaite.</p>
<p>Une des solutions est d&#8217;utiliser le tri par ordre alphabétique. C&#8217;est l&#8217;idéal pour l&#8217;affichage de contacts (par exemple). On peut même aller plus loin. Pourquoi simplement se limiter à un tri par ordre alphabétique ? Pourquoi ne pas proposer une catégorisation des entrées en prenant en compte la première lettre de la propriété qui nous intéresse. C&#8217;est ce que nous allons voir dans ce billet. Au final, nous arriverons à ce résultat:</p>
<p><a href="http://webd.fr/wp-content/uploads/2009/01/alphabeticaltableviewfinalscreen.png" rel="lightbox[237]" title="alphabeticaltableviewfinalscreen"><img src="http://webd.fr/wp-content/uploads/2009/01/alphabeticaltableviewfinalscreen-161x300.png" alt="alphabeticaltableviewfinalscreen" title="alphabeticaltableviewfinalscreen" width="161" height="300" class="aligncenter size-medium wp-image-274" /></a><br />
<span id="more-237"></span></p>
<p>On commence par créer notre projet dans Xcode et on lui ajoute un <code>TableViewController</code>. Pour le moment, on n&#8217;y touche pas. Ensuite, on créée le <code>xib</code> des cellules avec Interface Builder (pour plus de détails sur la manipulation de <code>UITableViewCell</code> avec Interface Builder, voir <a href="http://webd.fr/141-creer-une-uitableviewcell-personnalisee-a-partir-dinterface-builder"><cite>Créer une UITableViewCell personnalisée à partir d’Interface Builder</cite></a>). Maintenant, faisons une structure pour nos données. Ce sera une simple classe contenant 4 propriétés <code>NSString</code>: <code>firstname</code>, <code>lastname</code>, <code>age</code> et <code>sex</code>. Ce qui donne tout simplement:</p>
<pre lang="objc">@interface Person : NSObject {
    NSString *firstname;
    NSString *lastname;
    NSString *age;
    NSString *sex;
}</pre>
<p>On rajoute aussi les méthodes d&#8217;initialisation et de désallocation de l&#8217;objet: </p>
<pre lang="objc">
- (id) initWithLastName:(NSString *)mlastname andFirstname:(NSString *)mfirstname andSex:(NSString *)msex andAge:(NSString *)mage {
	lastname = [[NSString alloc] initWithString:mlastname];
	firstname = [[NSString alloc] initWithString:mfirstname];
	sex = [[NSString alloc] initWithString:msex];
	age = [[NSString alloc] initWithString:mage];
	return [super init];
}

- (void) dealloc {
	[lastname release];
	[firstname release];
	[sex release];
	[age release];
	[super dealloc];
}
</pre>
<p>Toute la partie <cite>manipulation de données</cite> sera gérée par <code>PersonDataSource</code>. Il s&#8217;agit d&#8217;une classe contenant:</p>
<ul>
<li>un <code>NSArray</code> (<code>personList</code>) qui contiendra notre liste de <code>Person</code> brute (c&#8217;est à dire non-triée)</li>
<li>un <code>NSMutableDictionary</code> (<code>personListAlphabeticalDictionary</code>) qui contiendra nos <code>Person</code> triées par ordre alphabétique. Chaque entrée du dictionnaire aura pour clef la première lettre du nom des <code>Person</code> et en valeur, le tableau de <code>Person</code> correspondant.</li>
<li>un <code>NSArray</code> (<code>personNameFirstLeterIndexArray</code>) qui contiendra la liste de toutes les premières lettres de noms disponibles. En effet, il se peut que l&#8217;on n&#8217;ai aucune entrée avec comme première lettre <cite>Z</cite> (par exemple).</li>
</ul>
<p>Du coté des méthodes, ça donne cela: </p>
<ul>
<li><code>- (void) populate</code>: cette méthode ne fait que récupérer nos objets <code>Person</code>. Dans l&#8217;exemple, j&#8217;ajoute les objets à la main, mais on peut tout à fait remplacer ça par une récupération de données dans un fichier XML ou bien une base de données.</li>
<li><code>- (void) populatePersonListAlphabeticalDictionary</code>: cette méthode va aller chercher le contenu de <code>personList</code> et générer <code>personListAlphabeticalDictionary</code> comme convenu. Pour finir, la méthode va appeler <code>sortPersonInitialLetterIndexes</code>.</li>
<li><code>- (void) sortPersonInitialLetterIndexes</code>: cette méthode va générer <code>personNameIndexArray</code> en récupérant toutes les clefs de <code>personListAlphabeticalDictionary</code> (triées alphabétiquement). Puis pour chacune des clefs, <code>presortPersonListAlphabeticalDictionaryForInitialLetter</code></li>
<li><code>- (void)presortPersonListAlphabeticalDictionaryForInitialLetter:(NSString *)aKey</code> va (pour une clef <code>aKey</code> donnée), trier le contenu du <code>NSArray</code> correspondant dans le <code>personListAlphabeticalDictionary</code>.</li>
<li><code>- (NSArray *)personsWithInitialLetter:(NSString*)aKey</code>: cette méthode retourne un <code>NSArray</code> avec toutes les <code>Person</code> ayant pour première lettre <code>aKey</code>.</li>
<li><code>- (Person *) personForIndexPath:(NSIndexPath *)indexPath</code> retourne l&#8217;objet <code>Person</code> correspondant au <code>NSIndexPath</code> passé en paramètre. Cette méthode sera appelée par le <code>UITableViewController</code>.</li>
</ul>
<p>Au final, on obtient ceci: </p>
<pre lang="objc">
- (id) init {
	[self populate];
	[self populatePersonListAlphabeticalDictionary];

	return [super init];

}
- (void) dealloc {

	[personList release];
	[personListAlphabeticalDictionary release];
	[personNameIndexArray release];
	[super dealloc];
}

- (void) populate {
	personList = [[NSMutableArray alloc] init];
	[personList addObject:[[Person alloc] initWithLastName:@"Léponge" andFirstname:@"Bob" andSex:@"Homme" andAge:@"21"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Daniel" andFirstname:@"Jack" andSex:@"Whiskey" andAge:@"12"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Fontaine" andFirstname:@"Claire" andSex:@"Femme" andAge:@"89"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Charues" andFirstname:@"Vielles" andSex:@"Festival" andAge:@"125"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Bull" andFirstname:@"Red" andSex:@"Boisson" andAge:@"2"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Bonvoisin" andFirstname:@"Bernie" andSex:@"Homme" andAge:@"55"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Jobs" andFirstname:@"Steeve" andSex:@"Homme" andAge:@"80"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Damien" andFirstname:@"Francois" andSex:@"Humoriste" andAge:@"35"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Gates" andFirstname:@"Bill" andSex:@"Homme" andAge:@"50"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Laporte" andFirstname:@"Bernard" andSex:@"Rugbyman" andAge:@"32"]];
	[personList addObject:[[Person alloc] initWithLastName:@"Chabal" andFirstname:@"Sebastien" andSex:@"Mythe" andAge:@"36"]];
}
- (void) populatePersonListAlphabeticalDictionary {
	personListAlphabeticalDictionary = [[NSMutableDictionary alloc] init];
	for(Person *currentPerson in personList)
	{

		NSString *firstLetter = [currentPerson.lastname substringToIndex:1];
		NSMutableArray *existingArray;
		/* Si on a déjà un array de Person pour cette première lettre*/
		if (existingArray = [personListAlphabeticalDictionary valueForKey:firstLetter])
		{
			/* On y ajoute la Person en cours*/
			[existingArray addObject:currentPerson];
		}
		else	/*Sinon, on créée l'array, on y ajoute la Person courante et on ajoute l'array au dictionnaire*/
		{
			NSMutableArray *tempArray = [NSMutableArray array];
			[tempArray addObject:currentPerson];
			[personListAlphabeticalDictionary setObject:tempArray forKey:firstLetter];
		}

	}

	/* On génère personNameIndexArray et on trie chaque array de personListAlphabeticalDictionary*/
	[self sortPersonInitialLetterIndexes];

}

- (void) sortPersonInitialLetterIndexes {
	personNameIndexArray = [[NSMutableArray alloc] init];
	/* On récupère toutes les premières lettres et on les trie en ignorant la case*/
	personNameIndexArray = [[personListAlphabeticalDictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
	for (NSString * eachNameIndex in personNameIndexArray)
	{
		[self presortPersonListAlphabeticalDictionaryForInitialLetter:eachNameIndex];
	}

}
- (void)presortPersonListAlphabeticalDictionaryForInitialLetter:(NSString *)aKey {
	/* Pour chaque array à la clef aKey dans le dictionnaire, on trie le contenu de l'array alphabétiquement sur la propriété lastname en ignorant la case*/
	NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastname"
																   ascending:YES
																	selector:@selector(localizedCaseInsensitiveCompare:)];
	NSArray *descriptors = [NSArray arrayWithObject:nameDescriptor];
	[[personListAlphabeticalDictionary objectForKey:aKey] sortUsingDescriptors:descriptors];
	[nameDescriptor release];
}
- (Person *) personForIndexPath:(NSIndexPath *)indexPath {
	/* On récupère la lettre qui a un ID correspondant à la section de l'indexPath */
	NSArray *personsWithInitLetter = [self personsWithInitialLetter:[personNameIndexArray objectAtIndex:indexPath.section]];
	/* Et on renvoie la Person correspondant au row*/
	return [personsWithInitLetter objectAtIndex:indexPath.row];
}

- (NSArray *)personsWithInitialLetter:(NSString*)aKey {
	/* On renvoie la liste des Person ayant pour première lettre aKey*/
	return [personListAlphabeticalDictionary objectForKey:aKey];
}
</pre>
<p>Maintenant que notre source de données est prête, il n&#8217;y a plus qu&#8217;à mettre en place la TableView en elle-même. La première chose est d&#8217;ajouter un <code>personDataSource</code> comme variable d&#8217;instance et de l&#8217;initialiser (via <code>[[PersonDataSource alloc]init];</code>). Ensuite, on attaque le <code><br />
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath</code>. Le fonctionement est traditionnel. La seule subtilité, c&#8217;est qu&#8217;on va récupérer l&#8217;objet <code>Person</code> via <code>[personDataSource personForIndexPath:indexPath]</code>. </p>
<p>Pour le nombre de sections dans la table, c&#8217;est simple: il y en aura autant que de première lettres. Donc, c&#8217;est tout naturellement que <code>- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView</code> renvera [[personDataSource personNameIndexArray] count]</code>. Pour le nombre de lignes dans chaque section, c'est le nombre de <code>Person</code> ayant pour première lettre celle qui correspond à la section courante. C'est pourquoi <code><br />
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section</code> retourne <code>return [[self miniContactsWithInitialLetter:[miniContactNameIndexArray  objectAtIndex:section]] count];</code>. On obtient donc ce code pour le <code>UITableViewController</code>: </p>
<pre lang="objc">

@implementation AlphaTableViewController
- (id)initWithStyle:(UITableViewStyle)style{
	if (self = [super initWithStyle:style])
	{
		personDataSource = [[PersonDataSource alloc]init];
		self.tableView.rowHeight = 125;
	}
	return self;
}

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

	static NSString *CellIdentifier = @"MyCellIdent";

    TableCell *cell = (TableCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    	UIViewController *c = [[UIViewController alloc] initWithNibName:@"TableViewCell"  bundle:nil];
		cell = (TableCell *)c.view;
		[c release];
    }
	Person *currentPerson = [personDataSource personForIndexPath:indexPath];

	[cell.firstname setText:[currentPerson firstname]];
	[cell.lastname setText:[currentPerson lastname]];
	[cell.sex setText:[currentPerson sex]];
	[cell.age setText:[currentPerson age]];	

    return cell;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [[personDataSource personNameIndexArray] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
	return [[personDataSource personsWithInitialLetter:[[personDataSource personNameIndexArray] objectAtIndex:section]] count];
}
</pre>
<p>Cela donne le résultat ci-dessous. C'est bien, mais il manque encore la liste des lettres sur la droite. C'est pas compliqué <img src='http://webd.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .<br />
<a href="http://webd.fr/wp-content/uploads/2009/01/alphabeticaltableviewmiddlescreen.png" rel="lightbox[237]" title="alphabeticaltableviewmiddlescreen"><img src="http://webd.fr/wp-content/uploads/2009/01/alphabeticaltableviewmiddlescreen-161x300.png" alt="alphabeticaltableviewmiddlescreen" title="alphabeticaltableviewmiddlescreen" width="161" height="300" class="aligncenter size-medium wp-image-275" /></a></p>
<p>En fait, il faut être capable de répondre à deux questions posées à l'<code>UITableViewController</code>: <cite>quels sont les titres à afficher pour l'index de la TableView</cite> via <code><br />
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView</code> et <cite>Pour la section X, où faut-il scroller la TableView</cite> via<br />
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index</code>. Au final, il est très facile de répondre à ces questions dans l'architecture que l'on a mis en place. Voilà ce que ça donne dans le code: </p>
<pre lang="objc">
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
	return [personDataSource personNameIndexArray];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
	return index;
}
</pre>
<p>Et le résultat final ... Vous l'avez déjà vu plus haut. Si vous voulez, vous trouverez <a href='http://webd.fr/wp-content/uploads/2009/01/alphatable.zip'>ici une archive du projet complet (Xcode 3.1)</a>.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/237-une-uitableview-triee-par-ordre-alphabetique/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Créer une UITableViewCell personnalisée à partir d’Interface Builder: exemple complet</title>
		<link>http://webd.fr/224-creer-uitableviewcell-personnalisee-interface-builder-exemple</link>
		<comments>http://webd.fr/224-creer-uitableviewcell-personnalisee-interface-builder-exemple#comments</comments>
		<pubDate>Fri, 09 Jan 2009 22:51:47 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=224</guid>
		<description><![CDATA[Il y a peu, j&#8217;exposais ma solution pour Créer une UITableViewCell personnalisée à partir d&#8217;Interface Builder. Suite au commentaire de Bruno Da Silva, je vous laisse une version complètement fonctionnelle de l&#8217;implémentation de cette méthode. Il s&#8217;agit d&#8217;une TableView qui va chercher les dernières photos Flickr avec pour tag « xmas ». Pourquoi donner un exemple aussi [...]]]></description>
			<content:encoded><![CDATA[<p>Il y a peu, j&#8217;exposais ma solution pour <cite><a href="http://webd.fr/141-creer-une-uitableviewcell-personnalisee-a-partir-dinterface-builder">Créer une UITableViewCell personnalisée à partir d&#8217;Interface Builder</a></cite>. Suite au <a href="http://webd.fr/141-creer-une-uitableviewcell-personnalisee-a-partir-dinterface-builder#comment-86">commentaire de Bruno Da Silva</a>, je vous laisse une version complètement fonctionnelle de l&#8217;implémentation de cette méthode. </p>
<p>Il s&#8217;agit d&#8217;une TableView qui va chercher les dernières photos Flickr avec pour tag « <cite>xmas</cite> ». Pourquoi donner un exemple aussi compliqué ? Tout simplement parce que je n&#8217;ai <b>vraiment</b> pas le temps de faire un exemple complet en ce moment et je voulais publier un exemple rapidement. J&#8217;ai donc récupéré rapidement un exemple de code que j&#8217;ai fais en interne pour le boulot. </p>
<p>La partie de code qui va chercher les images sur FlickR n&#8217;est pas de moi. L&#8217;auteur n&#8217;ayant pas laissé d&#8217;informations le concernant dans le code, je ne pourrais plus vous dire qui c&#8217;est (et ça me désole vraiment). </p>
<p>Voici l&#8217;archive contenant le projet Xcode complet (toute l&#8217;intelligence concernant la méthode pour l&#8217;<code>UITableViewCell</code> se trouve dans <code>MyTableViewController.m</code> à la méthode <code>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath</code>): télécharger <a href='http://webd.fr/wp-content/uploads/2009/01/mytableviewdemo.zip'>MyTableViewDemo.zip</a>.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/224-creer-uitableviewcell-personnalisee-interface-builder-exemple/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Réduire la hauteur d&#8217;une UITableView</title>
		<link>http://webd.fr/158-reduire-la-hauteur-dune-uitableview</link>
		<comments>http://webd.fr/158-reduire-la-hauteur-dune-uitableview#comments</comments>
		<pubDate>Mon, 05 Jan 2009 08:23:33 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=158</guid>
		<description><![CDATA[Prenons un cas simple: on a une UIView qui contient une simple UITableView (avec le UITableViewController qui va bien) ainsi qu&#8217;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 [...]]]></description>
			<content:encoded><![CDATA[<p>Prenons un cas simple: on a une <code>UIView</code> qui contient une simple <code>UITableView</code> (avec le <code>UITableViewController</code> qui va bien) ainsi qu&#8217;une <code>UIToolBar</code> en bas. On se retrouve avec un léger problème: la <code>UITableView</code> 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 <code>UIToolBar</code> a été volontairement mise en transparence pour illustrer le problème):</p>
<p><a href="http://webd.fr/wp-content/uploads/2008/12/uitableviewsizeproblem.png" rel="lightbox[158]" title="uitableviewsizeproblem"><img class="aligncenter size-medium wp-image-159" title="uitableviewsizeproblem" src="http://webd.fr/wp-content/uploads/2008/12/uitableviewsizeproblem-206x299.png" alt="uitableviewsizeproblem" width="206" height="299" /></a></p>
<p>Le souci, c&#8217;est qu&#8217;il n&#8217;est pas possible de préciser dans le code la taille d&#8217;une <code>UITableView</code>. Après avoir essayé plusieurs solutions (dont certaines était plutôt farfelue), j&#8217;en ai retenu une. C&#8217;est celle qui m&#8217;a semblé la plus propre, simple et efficace.<br />
<span id="more-158"></span><br />
Il s&#8217;agit tout simplement de créer une vue vide de la taille de la <code>UIToolBar</code> (par défaut: 44 pixels). Puis de la mettre en tant que <code>tableFooterView</code> (une vue qui n&#8217;est affichée que tout en bas de la <code>UITableView</code>) sur la <code>UITableView</code> courante. L&#8217;idéal c&#8217;est de faire ça directement dans la phase d&#8217;initialisation (dans le <code>UITableViewController</code>). Concrètement ça donne ça:</p>
<pre lang="objc">self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];</pre>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/158-reduire-la-hauteur-dune-uitableview/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Créer une UITableViewCell personnalisée à partir d&#8217;Interface Builder</title>
		<link>http://webd.fr/141-creer-une-uitableviewcell-personnalisee-a-partir-dinterface-builder</link>
		<comments>http://webd.fr/141-creer-une-uitableviewcell-personnalisee-a-partir-dinterface-builder#comments</comments>
		<pubDate>Fri, 26 Dec 2008 09:21:35 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=141</guid>
		<description><![CDATA[Le problème La TableView est un composant essentiel de l&#8217;HIM de l&#8217;iPhone très simple à développer pour des besoins simples. Clairement, si on doit afficher à l&#8217;utilisateur des cellules avec une seule ligne de texte, ça se fait les doigts dans le nez. Là où les choses se corsent, c&#8217;est quand il faut créer des [...]]]></description>
			<content:encoded><![CDATA[<h1>Le problème</h1>
<p>La TableView est un composant essentiel de l&#8217;HIM de l&#8217;iPhone très simple à développer pour des besoins simples. Clairement, si on doit afficher à l&#8217;utilisateur des cellules avec une seule ligne de texte, ça se fait les doigts dans le nez.</p>
<p>Là où les choses se corsent, c&#8217;est quand il faut créer des cellules personnalisées. Avec, par exemple, deux <code>UILabel</code> et une <code>UIImageView</code>. En effet, il n&#8217;existe pas de méthode pour charger un nib (comme l&#8217;habituel <code>initWithNibName:</code>). Ainsi, on se retrouve forcé à créer tout nos éléments et à les placer à la main dans le code. C&#8217;est loin d&#8217;être quelque chose d&#8217;agréable, simple et rapide à faire. Sans compter qu&#8217;au moindre changement de design de la cellule, on perd un temps fou.</p>
<h1>La solution</h1>
<p>Non, l&#8217;idéal c&#8217;est de pouvoir utiliser Interface Builder pour construire ses cellules&#8230; Après quelques essais, recherches et erreurs, voici la solution que j&#8217;ai trouvé (et que j&#8217;utilise):</p>
<p><span id="more-141"></span></p>
<p>On commence par créer une nouvelle interface dans IB. On y ajoute une TableCell (au passage, le nib ne doit contenir que des TableCell&#8217;s !). Dans la TableCell, on ajoute les éléments dont on a besoin (ici, deux <code>UILabel</code> et un <code>UIImageView</code>). On définit la <cite>Class Identity</cite> et les <cite>Class Outlets</cite> qui vont bien. On finit par un <cite>Write Classfile</cite> et on a notre nib et l&#8217;<code>UITableViewCell</code> dans le projet.<br />
<a href="http://webd.fr/wp-content/uploads/2008/12/tableviewcellxibscreen.jpg" rel="lightbox[141]" title="tableviewcellxibscreen"><img src="http://webd.fr/wp-content/uploads/2008/12/tableviewcellxibscreen-300x233.jpg" alt="tableviewcellxibscreen" title="tableviewcellxibscreen" width="300" height="233" class="aligncenter size-medium wp-image-150" /></a></p>
<p>Maintenant, il faut s&#8217;occuper de l&#8217;<code>UITableViewController</code>. L&#8217;utilisation d&#8217;un nib ne change absolument rien au fonctionnement habituel. Ce n&#8217;est qu&#8217;à la création de la cellule (dans <code>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath</code>) que cela change un peu. Voilà ce que ça donne:</p>
<pre lang="objc">(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"MyCellIdent";
    MyTableViewCell *cell = (MyTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    	// On initialise un ViewController à partir du Nib qui a été fait
    	UIViewController *c = [[UIViewController alloc] initWithNibName:@"MyTableViewCell"  bundle:nil];
	// On récupère sa vue et on la caste dans le type de notre TableViewCell
	cell = (MyTableViewCell *)c.view;
	[c release];
    }
    // Ensuite, ça reste traditionnel
    cell.label1.text = [[myObjects objectAtIndex:indexPath.row] name];
    cell.label2.text = [[myObjects objectAtIndex:indexPath.row] desc];
    [cell.uIImageView  setImage:[[myObjects objectAtIndex:indexPath.row] image]];
    return cell;
}</pre>
<p>Les développeurs avisés auront très certainement remarqué un petit détail qui a son importance: on ne définit jamais (lors de la création de la cellule) son <code>CellIdentifier</code>, ainsi la réutilisation de cellules devient impossible (ce qui est suicidaire en terme de mémoire). En fait, celui-ci se définit dans Interface Builder. Dans les propriétés de votre TableViewCell, il suffit de mettre votre <code>CellIndetifier</code> dans <cite>Identifier</cite>. Ici, on mettra donc <cite> MyCellIdent</cite>.</p>
<p>Vous voilà maintenant avec des TableViewCell générée à partir d&#8217;Interface Builder en gardant possible le mécanisme de ré-utilisation de cellules. Ça, c&#8217;est des demies journées de gagnées sur vos projets (si ils comportent des cellules personnalisées bien évidement).</p>
<p><strong>Édition du 09/01/09:</strong><br />
Un exemple de code complet et opérationnel est disponible dans le billet <cite><a href="http://webd.fr/224-creer-uitableviewcell-personnalisee-interface-builder-exemple">Créer une UITableViewCell personnalisée à partir d’Interface Builder: exemple complet</a></cite></p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/141-creer-une-uitableviewcell-personnalisee-a-partir-dinterface-builder/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Afficher l&#8217;image d&#8217;un contact de l&#8217;AddressBook de l’iPhone</title>
		<link>http://webd.fr/128-image-contact-addressbook-iphone</link>
		<comments>http://webd.fr/128-image-contact-addressbook-iphone#comments</comments>
		<pubDate>Sat, 20 Dec 2008 10:43:56 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=128</guid>
		<description><![CDATA[Il y a peu, je parlais de la sérialisation d&#8217;un contact dans l&#8217;AddressBook de l&#8217;iPhone. Toujours dans la même veine, voyons comment afficher, dans une application, la photographie d&#8217;un contact de l&#8217;AddressBook. L&#8217;idée est de partir du ABRecordRef correspondant au contact dont on souhaite afficher l&#8217;image. A partir de là, on vérifie que ce contact [...]]]></description>
			<content:encoded><![CDATA[<p>Il y a peu, je parlais de la <a href="http://webd.fr/120-serialiser-identifiant-contact-iphone">sérialisation d&#8217;un contact dans l&#8217;AddressBook de l&#8217;iPhone</a>. Toujours dans la même veine, voyons comment afficher, dans une application, la photographie d&#8217;un contact de l&#8217;AddressBook. </p>
<p>L&#8217;idée est de partir du <code>ABRecordRef</code> correspondant au contact dont on souhaite afficher l&#8217;image. A partir de là, on vérifie que ce contact dispose bien d&#8217;une photo dans sa fiche (via <code>ABPersonHasImageData()</code>. Pour finir, on récupère les données brutes de l&#8217;image (<code> ABPersonCopyImageData()</code>) et on crée la <code>UIImage</code> qui va bien (via <code>initWithData:</code>). </p>
<p>Au final, voilà ce que ça donne: </p>
<pre lang="objc">
if(ABPersonHasImageData(recordRef))
{
	NSData *myAvatarData = (NSData *) ABPersonCopyImageData(recordRef);
	UIImage *avatarImage = [[UIImage alloc] initWithData:myAvatarData];
	[myAvatarData release];
}
</pre>
<p>Après, il ne faut pas oublier de libérer <code>myAvatarData</code> puisqu&#8217;il est devenu inutile. Charge à vous ensuite d&#8217;afficher <code>avatarImage</code> dans le <code>UIImageView</code> qui va bien. Simple non ?</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/128-image-contact-addressbook-iphone/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Serialiser l&#8217;identifiant d&#8217;un contact dans l&#8217;AddressBook de l’iPhone</title>
		<link>http://webd.fr/120-serialiser-identifiant-contact-iphone</link>
		<comments>http://webd.fr/120-serialiser-identifiant-contact-iphone#comments</comments>
		<pubDate>Mon, 15 Dec 2008 11:16:21 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=120</guid>
		<description><![CDATA[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&#8217;idée ce coup là, c&#8217;est de récupérer un identifiant d&#8217;un contact. Je m&#8217;explique: dans l&#8217;application que je développe je dois enregistrer (sur un [...]]]></description>
			<content:encoded><![CDATA[<p>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 (« <a href="http://webd.fr/116-recuperer-une-adresse-email-dans-le-contactbook-de-liphone">Récupérer une adresse email dans le AddressBook de l’iPhone</a> »).</p>
<p>L&#8217;idée ce coup là, c&#8217;est de récupérer un identifiant d&#8217;un contact. Je m&#8217;explique: dans l&#8217;application que je développe je dois enregistrer (sur un serveur distant) des informations concernant un contact sélectionné par l&#8217;utilisateur. Clairement, il s&#8217;agit du nom, du prénom et de l&#8217;adresse email. Puis, dans un second temps, ces données peuvent revenir sur l&#8217;iPhone.</p>
<p>Seulement, il pourrait être intéressant de faire directement le lien, lors du retour de l&#8217;information, entre les personnes désignée par les données sur le serveur et l&#8217;entité qui la représente dans le AddressBook. Pourquoi ? Pour plusieurs raisons. Tout d&#8217;abord, imaginez que l&#8217;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&#8217;adresse mail). Et bien si on est capable de détecter ce changement quand les données reviennent sur l&#8217;iPhone, on pourra répercuter les modifications sur le serveur. La seconde raison est qu&#8217;il peut être sympa de faire un lien vers la fiche de la  personne dans le AddressBook quand on affiche son nom dans l&#8217;application.</p>
<p>Quand on arrive dans le <code> peoplePickerNavigationController: shouldContinueAfterSelectingPerson</code> (donc que l&#8217;utilisateur a sélectionne un contact), on ne dispose que d&#8217;un objet de type <code>ABRecordRef</code>. Ce type d&#8217;objet est difficilement « sérialisable » &#8230; Comprenez par là qu&#8217;il serait difficile de le transformer en une chaine de caractère et de refaire l&#8217;opération inverse (pour le « dé-sérialiser »).</p>
<p>La solution est d&#8217;utiliser <code> ABRecordGetRecordID()</code> qui retourne un identifiant unique du contact dans l&#8217; AddressBook. Cette fonction renvoie un objet de type <code>ABRecordID </code> (qui n&#8217;est ni plus ni moins qu&#8217;un entier !). Au final, pour la convertir en chaine de caractère ça donne (<code>mPerson</code> étant notre objet de type <code>ABRecordRef</code>):</p>
<pre lang="objc">NSString contactId = [NSString stringWithFormat:@"%u", ABRecordGetRecordID(mPerson)];</pre>
<p>Ensuite, l&#8217;opération inverse (récupérer le ABRecordRef a partir du de la chaine de caractère), c&#8217;est simple: </p>
<pre lang="objc">ABRecordRef recordRef = ABAddressBookGetPersonWithRecordID(addressBook, [contactId intValue]);</pre>
<p>Notez que dans le cas où le contact n&#8217;existe pas (plus), <code>ABAddressBookGetPersonWithRecordID()</code> renvoie <code>NULL</code>Voilà, maintenant on peut effectuer n&#8217;importe quelle opération comme si on venait de récupérer le contact à partir du <code> peoplePickerNavigationController</code>. </p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/120-serialiser-identifiant-contact-iphone/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Récupérer une adresse email dans le ContactBook de l&#8217;iPhone</title>
		<link>http://webd.fr/116-recuperer-une-adresse-email-dans-le-contactbook-de-liphone</link>
		<comments>http://webd.fr/116-recuperer-une-adresse-email-dans-le-contactbook-de-liphone#comments</comments>
		<pubDate>Thu, 21 Aug 2008 18:42:43 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa Touch]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=116</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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. </p>
<p>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 <code>peoplePickerNavigationController</code>). En effet, Mickaël Morvan le fait très bien dans son <a href="http://mikael-morvan.developpez.com/tutoriels/iphone/sdk/AdressBook/">article sur développez : « <cite>iPhone SDK: Accès au carnet d&#8217;adresses de l&#8217;iPhone</cite> »</a>. </p>
<p>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 <code>kABPersonEmailProperty</code> à la place de  <code>kABPersonLastNameProperty</code>), on lève une exception <code> Terminating_Due_To_Uncaught_Exception</code> … </p>
<p>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 <code>ABRecordCopyValue(mPerson,  kABPersonEmailProperty)</code> ne renverra pas une seule valeur mais une collection de valeurs ! Alors, évidement, quand on veut mettre ça dans un <code>NSString</code> ça ne passe pas.</p>
<p>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 :</p>
<pre lang="objc">NSString contactMail = (NSString *)ABMultiValueCopyValueAtIndex(ABRecordCopyValue(mPerson,  kABPersonEmailProperty), 0);</pre>
</p>
<p>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 <code>ABMultiValue</code>). </p>
<p>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 !</p>
<p style="text-align:center;"><a href='http://webd.fr/wp-content/uploads/2008/08/iphone-contact.jpg' rel="lightbox[116]" title="iphone-contact"><img src="http://webd.fr/wp-content/uploads/2008/08/iphone-contact-236x300.jpg" alt="" title="iphone-contact" width="236" height="300" class="alignnone size-medium wp-image-117" /></a></p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://webd.fr/116-recuperer-une-adresse-email-dans-le-contactbook-de-liphone/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
