<?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; Pro</title>
	<atom:link href="http://webd.fr/category/pro/feed" rel="self" type="application/rss+xml" />
	<link>http://webd.fr</link>
	<description>Le blog de Julien Quéré</description>
	<lastBuildDate>Thu, 17 Jun 2010 16:36:46 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>fr</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Pourquoi je n&#8217;utiliserais pas Google DNS</title>
		<link>http://webd.fr/1461-pourquoi-je-nutiliserais-pas-google-dns</link>
		<comments>http://webd.fr/1461-pourquoi-je-nutiliserais-pas-google-dns#comments</comments>
		<pubDate>Fri, 11 Dec 2009 08:07:41 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=1461</guid>
		<description><![CDATA[La semaine dernière, Google annonçait officiellement l&#8217;ouverture au public de son nouveau service: Google Public DNS. Il s&#8217;agit de proposer à tout internaute un service DNS qui se veut offrir une bien meilleure expérience du net à tout les utilisateurs&#8230;
DNS, c&#8217;est quoi ?
DNS (pour Domain Name System). Il s&#8217;agit du système qui traduit les noms [...]]]></description>
			<content:encoded><![CDATA[<p>La semaine dernière, <a href="http://googleblog.blogspot.com/2009/12/introducing-google-public-dns.html">Google annonçait officiellement</a> l&#8217;ouverture au public de son nouveau service: <em>Google Public DNS</em>. Il s&#8217;agit de proposer à tout internaute un service DNS qui se veut offrir une bien meilleure expérience du net à tout les utilisateurs&#8230;</p>
<h2>DNS, c&#8217;est quoi ?</h2>
<p>DNS (pour <em>Domain Name System</em>). Il s&#8217;agit du système qui traduit les noms de domaines (<em>webd.fr</em> par exemple) en adresses IP (<em>94.23.202.54</em> pour webd). En effet, les machines ne communiquent que par des adresses IP.</p>
<p>A moins d&#8217;être autiste, il est beaucoup plus simple de retenir des adresses textuelles. En fait, il faut voir DNS comme un annuaire du net. Il met en correspondance des noms de site avec des adresses IP. Là où un annuaire téléphonique met en relation des noms de personnes avec des numéros de téléphone.</p>
<p>Ce service DNS est totalement transparent pour les internautes car cela fait partie des services de base lors de la connexion à tout réseau (que ce soit le réseau de son FAI ou un réseau d&#8217;entreprise). Et voilà maintenant que Google lance son propre DNS publique et voudrait faire passer tout le Web par ce service.</p>
<p><span id="more-1461"></span></p>
<h2>Pas plus rapide qu’un autre</h2>
<p>L&#8217;argument de la firme de Mountain View est convaincant de prime abord: le but est d&#8217;offrir un service DNS beaucoup plus rapide. Google prétend que, grâce à son infrastructure réseau présente sur toute la planète, ils arrivent à répondre beaucoup plus rapidement aux requêtes DNS que les serveurs traditionnels. Ainsi, la traduction de nom de domaine en adresse IP se fait beaucoup plus vite. Donc, l&#8217;utilisateur a une expérience beaucoup plus agréable de son surf (puisque ses pages s&#8217;affichent plus vite).</p>
<p>L&#8217;argument n°1 de Google concerne la rapidité … Mais dans les faits, ce n&#8217;est pas ça du tout ! Enfin bon, nuançons quand même: ce n&#8217;est pas ralentissant non plus. C&#8217;est juste que je ne vois pas d&#8217;apport réel. J&#8217;ai fait quelques tests sur différents DNS: <em>Google Public DNS</em>, Free, Neuf et le serveur DNS local du SI sur lequel je me trouve.</p>
<p><img src="http://webd.fr/wp-content/uploads/2009/12/Google-Public-DNS-faster.gif" alt="Google-Public-DNS-faster" title="Google-Public-DNS-faster" width="131" height="60" class="aligncenter size-full wp-image-1493" /></p>
<p>Le résultat est sans appel: le DNS local l&#8217;emporte haut la main. Ça s&#8217;explique simplement par le fait que je n&#8217;ai pas besoin de passer par le réseau Internet pour le contacter. Il est en local avec moi. Et même si on retire cette mesure, <em>Google Public DNS</em> n&#8217;arrive premier que dans 2 cas sur 5 (et de peu).</p>
<p style="text-align: center;"><!-- 		@page { margin: 2cm } 		TD P { margin-bottom: 0cm } 		P { margin-bottom: 0.21cm } --></p>
<table style="text-align: center; height: 192px;" border="1" cellspacing="0" cellpadding="4" width="508" bordercolor="#000000">
<col width="57"></col>
<col width="45"></col>
<col width="51"></col>
<col width="51"></col>
<col width="51"></col>
<tbody>
<tr valign="top">
<td width="22%"></td>
<td width="18%">
<p style="margin-bottom: 0cm;">212.27.32.176<br />
Free</td>
<td width="20%">
<p style="margin-bottom: 0cm;">8.8.8.8<br />
Google</td>
<td width="20%">
<p style="margin-bottom: 0cm;">10.20.40.1<br />
DNS Local</td>
<td width="20%">
<p style="margin-bottom: 0cm;">80.118.192.100<br />
Neuf</td>
</tr>
<tr valign="top">
<td width="22%">Amazon.fr</td>
<td width="18%">29</td>
<td width="20%">23</td>
<td width="20%">13</td>
<td width="20%">12</td>
</tr>
<tr valign="top">
<td width="22%">Google.fr</td>
<td width="18%">29</td>
<td width="20%">49</td>
<td width="20%">18</td>
<td width="20%">12</td>
</tr>
<tr valign="top">
<td width="22%">Webd.fr</td>
<td width="18%">29</td>
<td width="20%"><span style="background: #ffff00 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">24</span></td>
<td width="20%">11</td>
<td width="20%">27</td>
</tr>
<tr valign="top">
<td width="22%">gandi.net</td>
<td width="18%">28</td>
<td width="20%"><span style="background: #ffff00 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">24</span></td>
<td width="20%">9</td>
<td width="20%">26</td>
</tr>
<tr valign="top">
<td width="22%">sxc.hu</td>
<td width="18%">28</td>
<td width="20%">23</td>
<td width="20%">9</td>
<td width="20%">23</td>
</tr>
<tr valign="top">
<td width="22%">developer.apple.com</td>
<td width="18%">30</td>
<td width="20%">23</td>
<td width="20%">11</td>
<td width="20%">12</td>
</tr>
</tbody>
</table>
<p style="margin-bottom: 0cm; text-align: center;">
<p>Donc, pour résumer: utiliser les <em>Google Public DNS</em> quand on a un serveur DNS en local est un suicide. De même, quand un FAI offre des DNS à ses clients, il les place aux plus près de ces derniers: dans son cœur de réseau. A titre d&#8217;information: quand on fait une requête DNS avec <em>Google Public DNS</em>, la requête passe aussi par le cœur de réseau du FAI, mais plutôt que de s&#8217;arrêter là, elle part sur Internet et arrive sur le réseau de Google. Pourquoi aller si loin?</p>
<p>Bref, dans toutes les mesures que j&#8217;ai pu faire (réseau d&#8217;entreprise branchée sur Oléane, réseau de l&#8217;école, Freebox dégroupée à la maison), <em>Google Public DNS</em> n&#8217;est pas plus rapide.</p>
<p>A titre d&#8217;information, voici le script bash que j&#8217;ai utilisé pour faire ces mesures (largement copié de <a href="http://www.manu-j.com/blog/opendns-alternative-google-dns-rocks/403/">ce billet</a>)</p>
<pre lang="bash">#!/bin/sh
for i in "webd.fr" "google.fr" "amazon.fr"  "gandi.net" "sxc.hu" "developer.app$
do
  for j in "80.118.192.100" "10.20.40.1" "8.8.8.8" "212.27.32.176"
  do
    echo $j $i `dig @$j $i | grep Query | awk -F ":" '{print $2}'`
  done
done</pre>
<h2>Pourquoi compliquer la vie de l&#8217;utilisateur ?</h2>
<p>Je ne sais pas vous, mais moi je suis un adapte du <em>Plug&#8217;n'play</em>. J&#8217;arrive sur un réseau, je branche mon cable et le DHCP s&#8217;occupe de tout … Je n&#8217;ai aucune configuration à faire. Pourquoi aller me compliquer la vie à rajouter des entrées DNS à la main alors que mon FAI (ou le DSI de mon entreprise) s&#8217;est décarcassé à faire un SI sans configuration requise ?</p>
<h2>Quid de l&#8217;impact sur les SI d&#8217;entreprise ?</h2>
<p>Aujourd&#8217;hui, Google annonce <em>Google Public DNS</em>. Demain, les utilisateurs quelque peu technophiles vont généraliser l&#8217;utilisation de ces DNS sur leurs machines: <cite>Ouais, moi j&#8217;utilise Google Public DNS, c&#8217;est la classe hein ? J&#8217;ai pas trop compris ce que ça fait, mais j&#8217;ai suivi un tutorial et depuis, il paraît que ça va plus vite</cite> …</p>
<p>A la limite, à la maison, on s&#8217;en fout. Mais en entreprise, c&#8217;est un coup à faire exploser les <em>helpdesk</em> des DSI. Quelques exemples concrets: aujourd&#8217;hui la plupart des entreprises ont des intranets, serveurs de partage, de facturations, … Bref: des serveurs internes. Pour y accéder, c&#8217;est souvent des noms bizzares qui sont utilisés. Par exemple: « poseidon.interne », « rennes.factu », « data.ora » …</p>
<p>Ces noms de domaines ne sont pas connus pas les serveurs DNS publics (à fortiori, par <em>Google Public DNS</em>). Donc, si vous n&#8217;utilisez pas les serveurs DNS internes à votre entreprise: vous ne pourrez plus accéder à ces services … J&#8217;entends déjà les coups de fils: <cite>Le serveur de facturation est innaccessible, vous foutez quoi ??? [...] Quoi, c’est même pas compatible avec Google ? Vous êtes des nazes !</cite>.</p>
<p>Bon, ça c&#8217;est pour le boulot … Vous en voulez pour la maison ? Si vous êtes chez Free, essayez donc d&#8217;accéder au disque de votre Freebox HD avec les <em>Google Public DNS</em> … Je sens que la hotline Free va être ravie …</p>
<p><a href="http://webd.fr/wp-content/uploads/2009/12/Google-Public-DNS-DSI.jpg" rel="lightbox[1461]"><img src="http://webd.fr/wp-content/uploads/2009/12/Google-Public-DNS-DSI-248x300.jpg" alt="Google-Public-DNS-DSI"  width="248" height="300" class="aligncenter size-medium wp-image-1496" /></a></p>
<h2>Encore un pouvoir de plus pour Google ?</h2>
<p>Aujourd’hui, Google est omniprésent dans notre accès internet au quotidien. Demain, si l’utilisation de <em>Google Public DNS</em> se généralise, Google aura un pouvoir fou sur notre navigation: même plus besoin de passer par une de leur page pour qu’ils sachent sur quel domaine on navigue. Plus loin encore: le service peut ne pas répondre de façon <em>honnête</em>. <a href="http://www.freenews.fr/spip.php?article7037">Voir le principe des DNS menteurs (chez Freenews)</a>. </p>
<p>Bon, je ne suis pas adepte de la théorie du complot <em>Google-CIA-Francs Maçons-Big Brother</em> &#8230; Mais quand même, la je ne vois pas du tout d&#8217;intérêt à donner un tel pouvoir à une société &#8230;</p>
<div id="attachment_1497" class="wp-caption aligncenter" style="width: 310px"><a href="http://webd.fr/wp-content/uploads/2009/12/Google-Public-DNS-Dont-be-evil.jpg" rel="lightbox[1461]"><img src="http://webd.fr/wp-content/uploads/2009/12/Google-Public-DNS-Dont-be-evil-300x174.jpg" alt="Don&#039;t be evil: la devise de Google"  width="300" height="174" class="size-medium wp-image-1497" /></a><p class="wp-caption-text">Don't be evil: la devise de Google</p></div>
<h2>Conclusion</h2>
<p>Pour conclure, je dirais simplement que je n’utiliserais pas <em>Google Public DNS</em>: ça ne m’apporte aucun gain de performance, ça risque d’impacter grandement mon <em>expérience utilisateurs</em> au sein des différents SI d’entreprise que j’utilise et ce serait donner trop de pouvoirs à Google.</p>
<p>Par contre, ce service à deux avantages: maintenant je connais une IP simple à pinguer: <em>8.8.8.8</em> pour les tests simples de connectivité. Le second avantage, c’est quand je mets en place une infrastructure réseau et que le DNS n’est pas encore fait, je connais une IP de DNS simple: <em>8.8.8.8</em>. Sinon, je continuerais à faire appel aux services de mon DSI ou FAI.</p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/1461-pourquoi-je-nutiliserais-pas-google-dns/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Oui, Windows est obligatoire à SUPINFO</title>
		<link>http://webd.fr/897-oui-windows-est-obligatoire-a-supinfo</link>
		<comments>http://webd.fr/897-oui-windows-est-obligatoire-a-supinfo#comments</comments>
		<pubDate>Thu, 20 Aug 2009 20:44:10 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=897</guid>
		<description><![CDATA[Il est rare (en fait c’est la première fois) que je parle de SUPINFO (école où je m&#8217;apprête a faire ma seconde année de Master) sur ces pages. Pourquoi commencer aujourd’hui ? Tout simplement parce qu’une rumeur enfle en ce moment au sujet de l’école. Le principal canal de diffusion: Twitter. 
L’idée de la rumeur [...]]]></description>
			<content:encoded><![CDATA[<p>Il est rare (en fait c’est la première fois) que je parle de SUPINFO (école où je m&#8217;apprête a faire ma seconde année de Master) sur ces pages. Pourquoi commencer aujourd’hui ? Tout simplement parce qu’une rumeur enfle en ce moment au sujet de l’école. Le principal canal de diffusion: Twitter. </p>
<p>L’idée de la rumeur est assez simple (simpliste ?): SUPINFO serait «macqué» avec Microsoft et obligerait tout ses étudiants à utiliser Windows sur leurs ordinateurs personnels. De là, on imagine rapidement le processus d’embrigadement visant à éloigner les étudiants du monde du logiciel libre (les élèves ingénieur d’aujourd’hui sont les décideurs de demain).<br />
<span id="more-897"></span><br />
Je ne suis pas connu pour être quelqu’un qui défend aveuglement SUPINFO (ça se vérifie &#8230;), mais cette rumeur m&#8217;énerve particulièrement pour la simple et bonne raison qu’elle est à mille lieux des faits. Tout d&#8217;abord, il faut comprendre quelques points propres à SUPINFO:</p>
<ul>
<li>Chaque étudiant vient en cours avec son propre ordinateur portable. Ceci pour les TP ou pour les cours magistraux</li>
<li>A SUPINFO, les évaluations se font de manière numérique sous forme de QCM. Ces évaluation (basées sur SGES: <i>SUPINFO Global Evaluation System</i>) sont passées par les étudiants sur leurs propres ordinateurs.</li>
</ul>
<p>Deux points qui ne sont pas secrets, qui sont même largement évoqués dans les brochures de l’école. Partant de là, on arrive à un problème simple: il faut que SGES (solution développée en interne par SUPINFO) permette à tout les étudiants de passer les évaluations de façon sécurisée et sans possibilité de triche &#8230; </p>
<p><a href="http://www.labo-linux.org/"><img src="http://webd.fr/wp-content/uploads/2009/08/laboLinux-300x38.jpg" alt="laboLinux" title="laboLinux" width="300" height="38" class="aligncenter size-medium wp-image-899" /></a></p>
<p>Pour des raisons de choix techniques (que je ne connais pas complètement mais qui me semblent logiques à priori), c’est le plateforme .Net qui a été choisie pour développer le client SGES. .Net, jusqu&#8217;à preuve du contraire, c’est pour Windows (oublions Mono). A cela, rajoutez que seul Windows est aussi contrôlable par le développeur. On a donc un client SGES .Net qui permet de passer les évaluations sans tricher (sans, par exemple, naviguer entre les fenêtres à coup de alt+tab pour lire son cours dans Word).</p>
<p>On ne peut pas exécuter le client SGES dans un environnement virtualisé car le propre de SGES est de bloquer l’écran de l’utilisateur. Il faut donc être certains que l&#8217;environnement sur lequel SGES client tourne n’est pas virtualisé, sinon ses protections anti-triche ne servent à rien: au lieu de faire un alt+tab sur l’OS qui héberger SGES, on le fait sur l’OS qui héberge VMWare (ou autre). Dernière question: pourquoi ne pas faire une autre version sur les autres plateformes (Linux, Mac OS X) ? Parce que ça prendrait un temps fou.</p>
<p>Donc, oui Windows (XP, Vista, Seven) est obligatoire à SUPINFO&#8230; Pour les évaluations SGES seulement ! Tout ce qui est demandé, c’est d’avoir une partition avec un Windows installé sur le disque dur de la machine. A coté de cela, mettez ce que vous voulez ! L’année dernière, sur mon portable SUPINFO, il y avait Windows XP, Ubuntu et Mac OS X (vive le multi boot)&#8230; Windows n’a été lancé que pour les évaluations. </p>
<p>Et puis en plus, les licences Windows sont offertes (via ELMS/MSDNAA) ! Alors de quoi se plaint-on ? Et bien en fait, nous les étudiants de SUPINFO, on ne se plaint pas du tout (de ça &#8230;). C’est ceux qui n’ont pas toutes ces informations qui voient un complot franc-maçonnique anti-Linux et anti-Mac &#8230; </p>
<p>Et puis, n’est-ce pas le propre d’un ingénieur: s’adapter à l&#8217;environnement qui entoure sa mission ? Si !</p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/897-oui-windows-est-obligatoire-a-supinfo/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<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]"><img src="http://webd.fr/wp-content/uploads/2009/06/image-6-300x224.png" alt="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>
]]></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/Foundation.h>

@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>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/637-comparer-deux-nsdate/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 8: Modifier le __MyCompanyName__</title>
		<link>http://webd.fr/707-developpement-iphone-modifier-le-__mycompanyname__</link>
		<comments>http://webd.fr/707-developpement-iphone-modifier-le-__mycompanyname__#comments</comments>
		<pubDate>Tue, 02 Jun 2009 08:12:37 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=707</guid>
		<description><![CDATA[Je vois assez souvent, dans les fichiers de code qui passent entre mes mains, des en-têtes comme ceci: 

//  Created by Julien on 17/01/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.

Le problème porte sur __MyCompanyName__. Il serait bien plus propre de le remplacer par une valeur personnalisée (et automatique de préférence). Pour ceci, Apple [...]]]></description>
			<content:encoded><![CDATA[<p>Je vois assez souvent, dans les fichiers de code qui passent entre mes mains, des en-têtes comme ceci: </p>
<pre lang="objc">
//  Created by Julien on 17/01/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
</pre>
<p>Le problème porte sur <code>__MyCompanyName__</code>. Il serait bien plus propre de le remplacer par une valeur personnalisée (et automatique de préférence). Pour ceci, Apple a tout prévu &#8230;<br />
<span id="more-707"></span><br />
Il suffit tout simplement de modifier <code>ORGANIZATIONNAME</code> de <code>PBXCustomTemplateMacroDefinitions</code> dans la configuration de Xcode. En ligne de commande, ça donne (dans mon cas):</p>
<pre lang="text">
defaults write com.apple.Xcode PBXCustomTemplateMacroDefinitions {"ORGANIZATIONNAME"="Julien Quéré - http://webd.fr";}'
</pre>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/707-developpement-iphone-modifier-le-__mycompanyname__/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Redimensionner une UIImage en étant Threadsafe</title>
		<link>http://webd.fr/631-redimensionner-une-uiimage-en-etant-threadsafe</link>
		<comments>http://webd.fr/631-redimensionner-une-uiimage-en-etant-threadsafe#comments</comments>
		<pubDate>Sat, 30 May 2009 07:47:26 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=631</guid>
		<description><![CDATA[Il y a peu, je vous présentais ici même comment redimensionner une UIImage. Je vous replace dans le contexte: 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’est pas [...]]]></description>
			<content:encoded><![CDATA[<p>Il y a peu, je vous présentais ici même comment <a href="http://webd.fr/320-redimensionner-une-uiimage">redimensionner une <code>UIImage</code></a>. Je vous replace dans le contexte: <cite>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’est pas forcement utile de stocker (en mémoire ou bien en dur) une image de grande taille si c’est pour l’afficher réduite par la suite</cite>.</p>
<p>Le code qui était présenté est fonctionnel … Oui, mais un collègue m&#8217;a fait remarquer que ce n&#8217;était pas le cas en multi-threads. Pourquoi ? Tout simplement parce que quand on fait <code>UIGraphicsBeginImageContext()</code>, on travaille dans un contexte unique. Ainsi, quand on voudra redimensionner deux images en même temps, elles partageront le même contexte. Clairement, ça ne peut pas marcher. D&#8217;ailleurs: ça ne marche pas !</p>
<p><span id="more-631"></span></p>
<p>Partant de là il y a deux options: soit on gère un système de sémaphore, soit on trouve un moyen de créer un contexte spécifique. L&#8217;idée du sémaphore est à exclure d&#8217;emblée. Ceci pour la simple et bonne raison qu&#8217;elle nous enlève l&#8217;avantage principal d&#8217;utiliser des threads: pouvoir exécuter des opérations en simultané. </p>
<p>Il faut donc créer un contexte bitmap spécifique à notre thread. Ensuite, on dessine notre image à redimensionner dans ce contexte que l&#8217;on vient de créer. Pour finir, on n&#8217;oubliera pas de libérer les différents refs créées. Dans le code, voilà ce que cela donne: </p>
<pre lang="objc">
//  UIImageAdditions.m
//  Untitled
//
//  Created by Julien on 28/05/09.
//  Copyright 2009 Julien Quéré - Webd.fr. All rights reserved.
//

#import "UIImageAdditions.h"

@implementation UIImage(UIImageAdditions)

- (UIImage *)resizeWithSize:(CGSize)size {
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 5, size.width*2, colorSpace, kCGImageAlphaNoneSkipFirst); //5bpc
	// size.width*2 = 2bbp
	CGRect rect = CGRectMake(0, 0, size.width, size.height);

	CGContextDrawImage(context, rect, self.CGImage);
	CGImageRef refNewImage = CGBitmapContextCreateImage(context);
	UIImage *newImage = [UIImage imageWithCGImage:refNewImage];

	CGImageRelease(refNewImage);
	CGColorSpaceRelease(colorSpace);
	CGContextRelease(context);

	return newImage;
}
@end

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

#import <Foundation/Foundation.h>

@interface UIImage(UIImageAdditions)
- (UIImage *)resizeWithSize:(CGSize)size;
@end
</pre>
<p>Pour l&#8217;utilisation de <code>CGBitmapContextCreate</code>, référez vous à <a href="http://developer.apple.com/iphone/library/documentation/GraphicsImaging/Reference/CGBitmapContext/Reference/reference.html#//apple_ref/doc/uid/TP30000947-CH1g-F16989">la littérature Apple sur le sujet</a>. La seule chose qui aurait besoin d&#8217;être explicité c&#8217;est le premier paramètre: le <code>NULL</code>. Le premier paramètre correspond à un pointeur où les données du contexte doivent être stockées. Quand on passe <code>NULL</code>, on indique en fait que l&#8217;on se fiche d&#8217;où les données seront stockées (ce qui est notre cas).</p>
<p>Une fois l&#8217;addition de <code>UIImage</code> mise en place, l&#8217;utilisation du code est assez simple: </p>
<pre lang="objc">
	UIImage *myPic = [UIImage imageNamed:@"poney.jpg"];
	[myPic resizeWithSize:CGSizeMake(50, 50)];
	[im setImage:myPic]; //im is an UIImageView
</pre>
<p>Merci à Loïc Dardant pour le code et le coup de main.</p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/631-redimensionner-une-uiimage-en-etant-threadsafe/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Calculer un hash MD5</title>
		<link>http://webd.fr/636-calculer-un-hash-md5</link>
		<comments>http://webd.fr/636-calculer-un-hash-md5#comments</comments>
		<pubDate>Tue, 19 May 2009 07:14:56 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=636</guid>
		<description><![CDATA[Pour ceux qui ne la connaissent pas, MD5 est une méthode permettant d&#8217;obtenir une empreinte numérique unique d&#8217;un message (au sens large du terme: chaine de caractère ou fichier). Cet algorithme a longtemps été utilisé à des fins de sécurité. Au risque de me répéter: n&#8217;utilisez pas MD5 à des fins de sécurité ! Cet [...]]]></description>
			<content:encoded><![CDATA[<p>Pour ceux qui ne la connaissent pas, MD5 est une méthode permettant d&#8217;obtenir une empreinte numérique unique d&#8217;un message (au sens large du terme: chaine de caractère ou fichier). Cet algorithme a longtemps été utilisé à des fins de sécurité. Au risque de me répéter: <strong>n&#8217;utilisez pas MD5 à des fins de sécurité</strong> ! Cet algorithme est maintenant faible. Plus d&#8217;informations sur <a href="http://en.wikipedia.org/wiki/MD5#Vulnerability">Wikipedia EN</a>.</p>
<p>MD5 peut être utilisé pour générer une clef &laquo;&nbsp;<i>unique</i>&nbsp;&raquo; à partir d&#8217;une chaine de caractères. Exemple concret: j&#8217;ai des objets représentant des rendez-vous qui naviguent un peu partout (SQLite local, serveur de calendrier distant, &#8230;). Il me faut à tout moment pouvoir identifier uniquement un rendez-vous. La solution que j&#8217;ai choisi est de générer une somme MD5 à partir du titre du rendez-vous, de la date de création et l&#8217;UDID (voir <a href="http://webd.fr/526-astuces-developpement-iphone-6-recuperer-ludid"><em>Comment récupérer l’UDID</em></a>). Voici l&#8217;implémentation que j&#8217;utilise pour générer mes MD5 (dans le cas présent, c&#8217;est une addition de <code>NSString</code>):<br />
<span id="more-636"></span></p>
<pre lang="objc">
//
//  NSStringAdditions.h
//  iMeeting
//
//  Created by Julien on 12/05/09.
//

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>

@interface NSString (NSStringAdditions)
- (NSString *)md5Hash;

@end
</pre>
<pre lang="objc">
//
//  NSStringAdditions.m
//  iMeeting
//
//  Created by Julien on 12/05/09.
//

#import "NSStringAdditions.h"

@implementation  NSString (NSStringAdditions)
- (NSString *)md5Hash
{
	const char *cStr = [self UTF8String];
	unsigned char result[CC_MD5_DIGEST_LENGTH];
	CC_MD5( cStr, strlen(cStr), result );
	return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
			result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
			result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]
			];
}
@end
</pre>
<p>Et un exemple simple d&#8217;utilisation:</p>
<pre lang="objc">
NSString *maChaine = [NSString stringWithString:@"MaChaineAMoi"]:
NSString *monMd5 = [maChaine md5Hash];
</pre>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/636-calculer-un-hash-md5/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 7: Deux NSDate sont-elles du même jour ?</title>
		<link>http://webd.fr/586-astuces-developpement-iphone-nsdate-comparaison-jour</link>
		<comments>http://webd.fr/586-astuces-developpement-iphone-nsdate-comparaison-jour#comments</comments>
		<pubDate>Fri, 15 May 2009 07:06:42 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=586</guid>
		<description><![CDATA[Voilà un problème simple qui s&#8217;est posé lors d&#8217;un de mes développement: comme vérifier si deux dates sont bien le même jour ? Ceci, en gardant les notions de fuseau horaires et compagnie. Bien que le problème soit simple, la solution n&#8217;est pas si anodine que cela.

Il s&#8217;agit, dans un premier temps, de préciser dans [...]]]></description>
			<content:encoded><![CDATA[<p>Voilà un problème simple qui s&#8217;est posé lors d&#8217;un de mes développement: comme vérifier si deux dates sont bien le même jour ? Ceci, en gardant les notions de fuseau horaires et compagnie. Bien que le problème soit simple, la solution n&#8217;est pas si anodine que cela.<br />
<span id="more-586"></span><br />
Il s&#8217;agit, dans un premier temps, de préciser dans quel calendrier on se situe. Ici, on est tout simple dans le calendrier <code>NSGregorianCalendar</code>. Ensuite, on extrait le composant de la date qui nous intéresse (ici: le jour). Puis, il ne reste plus qu&#8217;a comparer les deux composants extraits pour déterminer si les deux <code>NSDate</code> sont bien le même jour. </p>
<p>Voici la méthode qui fait cela (en étendant <code>NSDate</code> au passage) et l&#8217;utilisation: </p>
<p>Ajoute dans la classe NSDate en dérivant</p>
<pre lang="objc">
// Le .h
#import <Foundation/Foundation.h>

@interface NSDate (NSDateAdditions)
-(BOOL) isTheSameDayAsThisDate:(NSDate*)date;
@end
</pre>
<pre lang="objc">
// Le .m
@implementation NSDate (NSDateAdditions)

-(BOOL) isTheSameDayAsThisDate:(NSDate*)date {
	NSCalendar *gregorian = [[NSCalendar alloc]	initWithCalendarIdentifier:NSGregorianCalendar];
	NSDateComponents *comps1 = [gregorian components:NSDayCalendarUnit fromDate:date];
	NSDateComponents *comps2 = [gregorian components:NSDayCalendarUnit fromDate:self];
	[gregorian release];
	return ([comps1 isEqual:comps2]);
}

@end
</pre>
<pre lang="objc">
// startDate et endDate étant deux NSDate
if([startDate isTheSameDayAsThisDate:endDate])
{
	NSLog(@"startDate et endDate sont le même jour");
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/586-astuces-developpement-iphone-nsdate-comparaison-jour/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 6: Récupérer l&#8217;UDID</title>
		<link>http://webd.fr/526-astuces-developpement-iphone-6-recuperer-ludid</link>
		<comments>http://webd.fr/526-astuces-developpement-iphone-6-recuperer-ludid#comments</comments>
		<pubDate>Mon, 11 May 2009 09:14:54 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=526</guid>
		<description><![CDATA[Il peut être utile, dans une application, de connaître l'UDID de façon logicielle. Ainsi, on identifie de façon unique et certaine l'équipement sur lequel notre application s'exécute. Pour récupérer l'UDID, rien de plus simple ...]]></description>
			<content:encoded><![CDATA[<p>L&#8217;UDID (<i>Universal Device Identifier</i>) d&#8217;un iPhone est, comme son nom l&#8217;indique, un identifiant unique pour chaque iPhone / iPod. Si vous avez déjà eu à générer des fichiers de provisioning, vous connaissez bien cet identifiant. En effet, c&#8217;est ce dernier que l&#8217;on doit transmettre à Apple quand on veut rajouter un iPhone / iPod dans la liste des appareils autorisés pour un développement ou une distribution. </p>
<p>Il peut être utile, dans une application, de connaître ce fameux UDID de façon logicielle. Ainsi, on identifie de façon unique et certaine l&#8217;équipement sur lequel notre application s&#8217;exécute. Pour récupérer l&#8217;UDID, rien de plus simple:</p>
<pre lang="objc">
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
</pre>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/526-astuces-developpement-iphone-6-recuperer-ludid/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 5: whatis et ptype</title>
		<link>http://webd.fr/388-astuces-developpement-iphone-5-whatis-et-ptype</link>
		<comments>http://webd.fr/388-astuces-developpement-iphone-5-whatis-et-ptype#comments</comments>
		<pubDate>Wed, 06 May 2009 09:02:38 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=388</guid>
		<description><![CDATA[Dans la même veine que le Print Object en console, voici une nouvelle astuce en console de debug. L&#8217;idée n&#8217;est plus de récupérer la description d&#8217;un objet, mais son type. Ainsi, il y a deux commandes: whatis et ptype. La première permets d&#8217;avoir simplement le type d&#8217;un objet. Ainsi, si on a un objet monDico [...]]]></description>
			<content:encoded><![CDATA[<p>Dans la même veine que le <a href="http://webd.fr/385-astuces-developpement-iphone-2-print-object-en-console">Print Object en console</a>, voici une nouvelle astuce en console de debug. L&#8217;idée n&#8217;est plus de récupérer la description d&#8217;un objet, mais son type. Ainsi, il y a deux commandes: <code>whatis</code> et <code>ptype</code>. La première permets d&#8217;avoir simplement le type d&#8217;un objet. Ainsi, si on a un objet <code>monDico</code> de type <code>NSMutableDictionary</code>, voilà ce que l&#8217;on obtient avec <code>whatis</code>: </p>
<pre lang="objc">
(gdb) whatis monDico
type = NSMutableDictionary *
</pre>
<p><code>ptype</code>, quant à lui est beaucoup plus complet. Si on reprends le même exemple, voilà ce que l&#8217;on obtient: </p>
<pre lang="objc">
(gdb) ptype monDico
type = class NSMutableDictionary : public NSDictionary {
} *
</pre>
<p>Là où <code>ptype</code> prends tout son intérêt, c&#8217;est sur les types personnalisés. Voici deux exemple concret avec des objet perso: </p>
<pre lang="objc">
(gdb) ptype currentRdv
type = class MiniRdv : public NSObject {
  protected:
    NSString *startDateFormated;
    NSString *startTimeFormated;
    NSString *title;
    NSString *personName;
    NSString *personFirstName;
    NSString *personPhoneBookId;
    NSInteger dbId;
} *
</pre>
<pre lang="objc">
(gdb) ptype cell
type = class RdvTableCell : public UITableViewCell {
  protected:
    MiniRdv *miniRdvObject;
    UILabel *topLeftLabel;
    UILabel *bottomLeftLabel;
    UILabel *bottomRightLabel;
    UILabel *topRightLabel;
    UIImageView *avatar;
} *
</pre>
<p>Bref, <code>ptype</code> est un outil indispensable au debug d&#8217;applications !</p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/388-astuces-developpement-iphone-5-whatis-et-ptype/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 4: Récupérer le nom de l&#8217;iPhone</title>
		<link>http://webd.fr/420-astuces-developpement-iphone-4-recuperer-le-nom-de-liphone</link>
		<comments>http://webd.fr/420-astuces-developpement-iphone-4-recuperer-le-nom-de-liphone#comments</comments>
		<pubDate>Fri, 01 May 2009 07:56:02 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=420</guid>
		<description><![CDATA[Il peut être très utile de récupérer le nom de l&#8217;iPhone sur lequel notre application s&#8217;exécute (comme iPhone-de-julien). C&#8217;est le cas notamment dans des applications où on appaire deux iPhone au travers d&#8217;un réseau WiFi (par exemple). L&#8217;idée est très simple: on récupère les informations de l&#8217;hôte courant, puis on prend le premier de ses [...]]]></description>
			<content:encoded><![CDATA[<p>Il peut être très utile de récupérer le nom de l&#8217;iPhone sur lequel notre application s&#8217;exécute (comme <cite>iPhone-de-julien</cite>). C&#8217;est le cas notamment dans des applications où on appaire deux iPhone au travers d&#8217;un réseau WiFi (par exemple). L&#8217;idée est très simple: on récupère les informations de l&#8217;hôte courant, puis on prend le premier de ses noms. Ce qui donne au final:</p>
<pre lang="objc">
NSString *deviceName = [[[NSHost currentHost] names] objectAtIndex:0];
</pre>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/420-astuces-developpement-iphone-4-recuperer-le-nom-de-liphone/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 3: Executer un code seulement sur le simulateur</title>
		<link>http://webd.fr/415-iphone-executer-code-seulement-le-simulateur</link>
		<comments>http://webd.fr/415-iphone-executer-code-seulement-le-simulateur#comments</comments>
		<pubDate>Mon, 27 Apr 2009 09:14:00 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=415</guid>
		<description><![CDATA[Il peut être utile parfois de n&#8217;exécuter certains codes que dans le simulateur (ou à l&#8217;inverse: seulement sur un véritable iPhone). Concrètement, c&#8217;est le cas quand on utilise des fonctionnalités non présentes sur le simulateur (accéléromètre par exemple). Pour ce faire, il suffit d&#8217;inclure le code a exécuter sur simulateur entre des directives de compilateur: [...]]]></description>
			<content:encoded><![CDATA[<p>Il peut être utile parfois de n&#8217;exécuter certains codes que dans le simulateur (ou à l&#8217;inverse: seulement sur un véritable iPhone). Concrètement, c&#8217;est le cas quand on utilise des fonctionnalités non présentes sur le simulateur (accéléromètre par exemple). Pour ce faire, il suffit d&#8217;inclure le code a exécuter sur simulateur entre des directives de compilateur: </p>
<pre lang="objc">
#if TARGET_IPHONE_SIMULATOR
  NSLog(@"Bonjour, je suis sir le simulateur");
#else
  NSLog(@"Bonjour, je suis sur un véritable iPhone !");
#endif
</pre>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/415-iphone-executer-code-seulement-le-simulateur/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 2: Print Object en console</title>
		<link>http://webd.fr/385-astuces-developpement-iphone-2-print-object-en-console</link>
		<comments>http://webd.fr/385-astuces-developpement-iphone-2-print-object-en-console#comments</comments>
		<pubDate>Mon, 20 Apr 2009 08:30:24 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=385</guid>
		<description><![CDATA[Je me suis très souvent posé la question suivante: Mais pourquoi ça ne marche pas ? Qu&#8217;est ce qu&#8217;il y a dans cet objet ?. Le fait est que ce n&#8217;est pas très facile de répondre à cette question avec l&#8217;interface de débogage de Xcode. Par contre dans la console de debug, il y a [...]]]></description>
			<content:encoded><![CDATA[<p>Je me suis très souvent posé la question suivante: <cite>Mais pourquoi ça ne marche pas ? Qu&#8217;est ce qu&#8217;il y a dans cet objet ?</cite>. Le fait est que ce n&#8217;est pas très facile de répondre à cette question avec l&#8217;interface de débogage de Xcode. Par contre dans la console de debug, il y a une commande magnifique … </p>
<p>Il s&#8217;agit tout simplement de <code>po</code> (pour <i>Print Object</i>). Pour l&#8217;utiliser, rien de plus simple: mettez un point d&#8217;arrêt là où vous voulez voir ce que contient un objet. Ensuite, faites un simple <code>po monObjet</code>. Par exemple, créons un <code>NSMutableDictionary</code> … </p>
<pre lang="objc">
NSMutableDictionary * monDico = [[NSMutableDictionary alloc] init];
[monDico setObject:@"objet1" forKey:@"clef1"];
[monDico setObject:@"objet2" forKey:@"clef2"];
[monDico setObject:@"objet3" forKey:@"clef3"];
[monDico setObject:@"objet4" forKey:@"clef4"];
[monDico setObject:@"objet5" forKey:@"clef5"];
</pre>
<p>Et voilà ce que nous renvoie la console après un <code>po monDico</code></p>
<pre lang="objc">
(gdb) po monDico
{
    clef1 = objet1;
    clef2 = objet2;
    clef3 = objet3;
    clef4 = objet4;
    clef5 = objet5;
}
</pre>
<p>En fait, <code>po</code> fait appel à la méthode <code>description</code> de l&#8217;objet. Toutes les classes Cocoa de base implémentent cette méthode. Pour les classes personnelles, il vous suffit d&#8217;implémenter le protocole suivant: <code>- (NSString *)description;</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/385-astuces-developpement-iphone-2-print-object-en-console/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Astuces développement iPhone 1: Quelques raccourcis claviers</title>
		<link>http://webd.fr/378-astuces-developpement-iphone-1-quelques-raccourcis-claviers</link>
		<comments>http://webd.fr/378-astuces-developpement-iphone-1-quelques-raccourcis-claviers#comments</comments>
		<pubDate>Mon, 13 Apr 2009 09:06:59 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Developpement]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=378</guid>
		<description><![CDATA[Au cours de mes développements iPhone, il y a plein de petites astuces que je découvre. Des petites choses toute bêtes, mais elles peuvent faire gagner pas mal de temps et de confort quand on les utilise les uns à la suite des autres. Voilà pourquoi je pense lancer une série de billets où je [...]]]></description>
			<content:encoded><![CDATA[<p>Au cours de mes développements iPhone, il y a plein de petites astuces que je découvre. Des petites choses toute bêtes, mais elles peuvent faire gagner pas mal de temps et de confort quand on les utilise les uns à la suite des autres. Voilà pourquoi je pense lancer une série de billets où je présenterais les astuces découvertes au fil du temps. </p>
<p>Commençons donc par quelques raccourcis claviers découverts récemment qui me font gagner pas mal de temps: </p>
<ul>
<li><b>Option et double clic</b>: affiche la documentation pour ce qui se trouve sous le curseur (si la documentation existe bien évidement). </li>
<li><b>Commande et double clic</b>: envoie vers la définition (dans le .h) de ce qui se trouve sous le curseur.</li>
<li><b>Commande-Option-Haut</b>: permets de switcher entre le fichier d&#8217;en-tête (.h) et de code (.m) et vice-versa.</li>
<li><b>Commande-B</b>: lance la compilation du projet.</li>
<li><b>Commande-Retour</b>: compile le projet et le lance.</li>
</ul>
<p>Sinon, pour ceux qui veulent un grand poster, il y a l&#8217;image faite par <a href="http://cocoasamurai.blogspot.com/2008/02/complete-xcode-keyboard-shortcut-list.html">Colin Wheeler de Cocoa Samurai</a>. Elle est très (trop ?) complète:</p>
<p><a href="http://webd.fr/wp-content/uploads/2009/04/xcode-shortcuts.png" rel="lightbox[378]"><img src="http://webd.fr/wp-content/uploads/2009/04/xcode-shortcuts-290x300.png" alt="xcode-shortcuts"  width="290" height="300" class="aligncenter size-medium wp-image-381" /></a></p>
<p>A bientôt (certainement) pour de nouvelles astuces … </p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/378-astuces-developpement-iphone-1-quelques-raccourcis-claviers/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Décompresser des archives dans des dossiers multiples sous MacOS</title>
		<link>http://webd.fr/327-decompresser-des-archives-dans-des-dossiers-multiples-sous-mac</link>
		<comments>http://webd.fr/327-decompresser-des-archives-dans-des-dossiers-multiples-sous-mac#comments</comments>
		<pubDate>Wed, 25 Mar 2009 14:46:51 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Script]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=327</guid>
		<description><![CDATA[J&#8217;avais fait pas mal de billets sur ce blog concernant un script de décompression d&#8217;archives multiples en rar sous Linux (le dernier ici). L&#8217;idée est de porter la processus sur Mac OS. Premier problème: il n&#8217;y a pas de commande rar (ni même unrar) par défaut (même avec UnrarX). 
Pour corriger cela, il suffit de [...]]]></description>
			<content:encoded><![CDATA[<p>J&#8217;avais fait pas mal de billets sur ce blog concernant un script de décompression d&#8217;archives multiples en <code>rar</code> sous Linux (<a href="http://webd.fr/145-decompresser-des-archives-dans-des-dossiers-multiples-sous-linux-3">le dernier ici</a>). L&#8217;idée est de porter la processus sur Mac OS. Premier problème: il n&#8217;y a pas de commande <code>rar</code> (ni même <code>unrar</code>) par défaut (même avec UnrarX). </p>
<p>Pour corriger cela, il suffit de se rendre sur le site de <a href="http://www.rarlab.com/download.htm">rarlab</a> et de télécharger la version MacOS X de rar. Une fois le téléchargement décompressé, il suffit de déplacer les exécutables qui vont bien dans <code>/usr/bin</code>. Pour ce faire: </p>
<pre>
mac-de-julien:rar julien$ sudo mv unrar /usr/bin
mac-de-julien:rar julien$ sudo mv rar /usr/bin
</pre>
<p>Pour finir, il suffit d&#8217;utiliser le script habituellement utilisé sur Linux et c&#8217;est bon &#8230; Vous le trouverez <a href="http://webd.fr/145-decompresser-des-archives-dans-des-dossiers-multiples-sous-linux-3">par là</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/327-decompresser-des-archives-dans-des-dossiers-multiples-sous-mac/feed</wfw:commentRss>
		<slash:comments>0</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>
]]></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]"><img src="http://webd.fr/wp-content/uploads/2009/02/disablenslogscreen-281x300.png" alt="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>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/307-desactiver-les-nslog-en-release/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Le retour du canard sous Mac OS X</title>
		<link>http://webd.fr/298-le-retour-du-canard-sous-mac-os-x</link>
		<comments>http://webd.fr/298-le-retour-du-canard-sous-mac-os-x#comments</comments>
		<pubDate>Fri, 06 Feb 2009 08:21:49 +0000</pubDate>
		<dc:creator>Julien Quéré</dc:creator>
				<category><![CDATA[Pro]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Perte de temps]]></category>

		<guid isPermaLink="false">http://webd.fr/?p=298</guid>
		<description><![CDATA[Il y a quelques temps maintenant, j&#8217;ai fais l&#8217;acquisition d&#8217;un Mac (même si j&#8217;ai un Mac professionnel depuis pas mal de temps). Et bizarrement l&#8217;une des choses inutiles mais indispensables que j&#8217;attendais, c&#8217;était le fameux son de canard en guise d&#8217;alerte. Concrètement, on a le droit à un « coin » à chaque alerte de l&#8217;OS. [...]]]></description>
			<content:encoded><![CDATA[<p>Il y a quelques temps maintenant, j&#8217;ai fais l&#8217;acquisition d&#8217;un Mac (même si j&#8217;ai un Mac professionnel depuis pas mal de temps). Et bizarrement l&#8217;une des choses inutiles mais indispensables que j&#8217;attendais, c&#8217;était le fameux son de canard en guise d&#8217;alerte. Concrètement, on a le droit à un « coin » à chaque alerte de l&#8217;OS. </p>
<p>Après avoir cherché quelque peu, je m&#8217;aperçois avec effroi que ce son n&#8217;est tout simplement pas présent sous Léopard. En poussant un peu mes recherches, je me rends compte que c&#8217;est le cas depuis Mac OS X 10.0 (comme quoi ma précédente expérience Mac OS non-pro remontait à loin !). </p>
<p>Après quelques recherches (non, je n&#8217;abandonne pas, même pour de telles futilités), j&#8217;ai trouvé comment combler ce manque. Il suffit de télécharger <a href='http://webd.fr/wp-content/uploads/2009/02/macosxoldschoolsoundsdmg.tgz'>l&#8217;archive ci-jointe</a> (qui contient les sons système depuis System 6 jusqu&#8217;à Mac OS 9). Ensuite, il faut mettre les fichiers <code>.aiff</code> dans <code>/Bibliothèque/Sounds/</code>. Si le dossier <code>Sounds</code> n&#8217;existe pas, créez le. </p>
<p><a href="http://webd.fr/wp-content/uploads/2009/02/image-5.png" rel="lightbox[298]"><img src="http://webd.fr/wp-content/uploads/2009/02/image-5-300x111.png" alt="image-5"  width="300" height="111" class="aligncenter size-medium wp-image-300" /></a></p>
<p>Après avoir redémarré votre machine, rendez vous dans les <cite>Préférences systèmes</cite> puis <cite>Sons</cite> puis <cite>Effets sonores</cite>. Vous pourrez maintenant choisir le son qui vous plait. Ici, c&#8217;est bien évidement le canard !</p>
<p><a href="http://webd.fr/wp-content/uploads/2009/02/image-6.png" rel="lightbox[298]"><img src="http://webd.fr/wp-content/uploads/2009/02/image-6-300x227.png" alt="image-6"  width="300" height="227" class="aligncenter size-medium wp-image-301" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/298-le-retour-du-canard-sous-mac-os-x/feed</wfw:commentRss>
		<slash:comments>3</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>
]]></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). On [...]]]></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]"><img src="http://webd.fr/wp-content/uploads/2009/01/alphabeticaltableviewfinalscreen-161x300.png" alt="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]"><img src="http://webd.fr/wp-content/uploads/2009/01/alphabeticaltableviewmiddlescreen-161x300.png" alt="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>
]]></content:encoded>
			<wfw:commentRss>http://webd.fr/237-une-uitableview-triee-par-ordre-alphabetique/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
