cocoaheads rennes #3 : bien coder sur ios

45
Bien coder Sur iOS Julien QUERE [email protected] CocoaHeads Rennes 8 septembre 2011

Upload: cocoaheadsrns

Post on 25-May-2015

3.020 views

Category:

Technology


0 download

DESCRIPTION

Slides de la présentation "Bien coder sur iOS" de la session des CocoaHeads Rennais du 08 septembre 2011. Présentation assurée par Julien Quéré, co-organisateur.

TRANSCRIPT

Page 1: Cocoaheads Rennes #3 : Bien coder sur iOS

Bien coderSur iOS

Julien [email protected]

CocoaHeads Rennes8 septembre 2011

Page 2: Cocoaheads Rennes #3 : Bien coder sur iOS

Pour qui ? Pourquoi ?Pour l’utilisateur

✓Compréhensibilité

✓Flexibilité

✓Réutilisabilité

‣ Maintenance et évolutions plus aisés

‣ Projets plus rapides

➡Gain de temps

➡Gain en réactivité

Pour le futur✓ Performance

✓ Stabilité

‣ Moins de bugs

‣ Moins de retours

‣ Une meilleure expérience utilisateur/client

➡ Gain de temps

➡ Gain en crédibilité

Page 3: Cocoaheads Rennes #3 : Bien coder sur iOS

J.

« L’important, ce n’est pas les règles, c’est le fait d’en avoir »

Coding guidelines

Page 4: Cocoaheads Rennes #3 : Bien coder sur iOS

Formatage- (NSURL*) url {! NSString * url = [NSString stringWithString:kWDGdirectionsBaseURL];! NSDictionary * parameters = [self parameters];!! if(parameters)! {! BOOL isFirstKey = YES;! ! ! ! NSString * separator = @"?";! !! ! ! for (NSString * key in [parameters allKeys]) {! ! ! url = [url stringByAppendingFormat:@"%@%@=%@", separator, key, [parameters valueForKey:key]];! ! !! ! ! if(isFirstKey)! ! {! ! ! isFirstKey = NO;! ! ! ! separator = @"&";! ! ! }! ! }! ! }! ! ! ! ! url = [url stringByAddingPercentEscapesUsingEncoding:! ! NSUTF8StringEncoding];! return [NSURL URLWithString:url];}

Page 5: Cocoaheads Rennes #3 : Bien coder sur iOS

Formatage- (NSURL*) url {! NSString * url = [NSString stringWithString:kWDGdirectionsBaseURL];! NSDictionary * parameters = [self parameters];!! if(parameters) {! ! BOOL isFirstKey = YES;! ! NSString * separator = @"?";! !! ! for (NSString * key in [parameters allKeys]) {! ! ! url = [url stringByAppendingFormat:@"%@%@=%@", separator, key, [parameters valueForKey:key]];! ! !! ! ! if(isFirstKey) {! ! ! ! isFirstKey = NO;! ! ! ! separator = @"&";! ! ! }! ! }! }! url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];! return [NSURL URLWithString:url];}

Page 6: Cocoaheads Rennes #3 : Bien coder sur iOS

Formatage

➡ Un code propre = code compréhensible

➡ Surveiller: l’indentation, le placement des délimiteurs, ...

Page 7: Cocoaheads Rennes #3 : Bien coder sur iOS

NommageIl faut pouvoir facilement différencier:

➡ Une variable statique

➡ Une variable d’instance

➡ Un attribut

➡ Une variable de classe

➡ Une variable locale

Page 8: Cocoaheads Rennes #3 : Bien coder sur iOS

La règle de 3

➡ Je développe une routine une fois

➡ Seconde fois: je me pose des questions

➡ Troisième fois: je factorise

Page 9: Cocoaheads Rennes #3 : Bien coder sur iOS

- (void) displayTopTweets:(NSArray*)tweets {

!

!

! !

! !}

! if([tweets count] == 4) {! ! [tweetButton1_.titleLabel setNumberOfLines:2];! ! [tweetButton1_ setTitle:[tweets objectAtIndex:0]! ! ! ! ! forState:UIControlStateNormal];! ! [tweetButton1_ setTitle:[[tweets objectAtIndex:0] uppercaseString]! ! ! ! ! forState:UIControlStateHighlighted];! ! [tweetButton1_ setHidden:NO];!! ! [tweetButton2_.titleLabel setNumberOfLines:2];! ! [tweetButton2_ setTitle:[tweets objectAtIndex:1]! ! ! ! ! forState:UIControlStateNormal];! ! [tweetButton2_ setTitle:[[tweets objectAtIndex:1] uppercaseString]! ! ! ! ! forState:UIControlStateHighlighted];! ! [tweetButton2_ setHidden:NO];! !! ! [tweetButton3_.titleLabel setNumberOfLines:2];! ! [tweetButton3_ setTitle:[tweets objectAtIndex:2]! ! ! ! ! forState:UIControlStateNormal];! ! [tweetButton3_ setTitle:[[tweets objectAtIndex:2] uppercaseString]! ! ! ! ! forState:UIControlStateHighlighted];! ! [tweetButton3_ setHidden:NO];! !! ! [tweetButton4_.titleLabel setNumberOfLines:2];! ! [tweetButton4_ setTitle:[tweets objectAtIndex:3]! ! ! ! ! forState:UIControlStateNormal];! ! [tweetButton4_ setTitle:[[tweets objectAtIndex:3] uppercaseString]! ! ! ! ! forState:UIControlStateHighlighted];! ! [tweetButton4_ setHidden:NO];!!! }

Page 10: Cocoaheads Rennes #3 : Bien coder sur iOS

- (void) displayTopTweets:(NSArray*)tweets {

!

!

! !

! !

! ! ! [button.titleLabel setNumberOfLines:2];! ! ! [button setTitle:tweet! ! ! ! ! forState:UIControlStateNormal];! ! ! [button setTitle:[tweet uppercaseString]! ! ! ! ! forState:UIControlStateHighlighted];! ! ! [button setHidden:NO];

! NSArray * buttons = [NSArray arrayWithObjects:tweetButton1_, tweetButton2_, ! ! ! ! ! ! tweetButton3_, tweetButton4_, nil];

! if([buttons count] == [tweets count]) {! ! for (NSUInteger i = 0; i < [buttons count]; i++) {

! ! ! ! ! }! }

! ! ! UIButton * button = [buttons objectAtIndex:i];! ! ! NSString * tweet = [tweets objectAtIndex:i];

}

Page 11: Cocoaheads Rennes #3 : Bien coder sur iOS

Utiliser des constantes

➡ Pas de valeur numérique / textuelle «en dur»

➡ Utiliser des constantes

➡ Utiliser un fichier de locales

Page 12: Cocoaheads Rennes #3 : Bien coder sur iOS

Définir ses propres guidelines

➡ Prendre le temps et du recul

➡ Intégrer toute l’équipe dans le processus

➡ Ne pas hésiter à se baser sur des guidelines existantes

http://google-styleguide.googlecode.com/svn/trunk/objcguide.xml

Google Objective-C Style Guide

Page 13: Cocoaheads Rennes #3 : Bien coder sur iOS

Jean-Pierre Florian

« Quand on est pauvre, on n'a que la ressource d'être sage. »

Gestion intelligente des ressources

Page 14: Cocoaheads Rennes #3 : Bien coder sur iOS

Quelles ressources ?

Batterie Echanges réseau

Mémoire

Page 15: Cocoaheads Rennes #3 : Bien coder sur iOS

Batterie

➡ CPU

➡ Radio (Wi-Fi, Bluetooth, GPS, EDGE/3G)

➡ Accéléromètre / gyroscope

➡ Boussole

➡ Disque (stockage flash)

➡ Ecran

Pour gagner en autonomie, iOS désactive le materiel dés que possible:

C’est en réduisant l’usage de ces matériels que l’on

augmente l’autonomie

Page 16: Cocoaheads Rennes #3 : Bien coder sur iOS

Batterie: L’exemple Core Location

➡ Solution simple: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ! manager_ = [[CLLocationManager alloc] init];! manager_.desiredAccuracy = kCLLocationAccuracyBestForNavigation;! manager_.delegate = self;! [manager_ startUpdatingLocation];

➡Core Location va mettre à jour la position en continu ...

➡... jusqu'à ce que la batterie soit vide

➡ Core Location va mettre à jour la position en continu ...

➡ ... jusqu'à ce que la batterie soit vide

Page 17: Cocoaheads Rennes #3 : Bien coder sur iOS

Batterie: L’exemple Core Location

➡ Solution économique:

➡ Ne lancer Core Location que quand c’est nécessaire

➡ Régler la précision avec intelligence

➡ Ne pas laisser tourner Core Location inutilement

Page 18: Cocoaheads Rennes #3 : Bien coder sur iOS

Batterie - Mais aussi➡ Eviter tout calcul inutile

➡ Ne jamais utiliser [application setIdleTimerDisabled:YES] sans raison

➡ Eviter les accès trop fréquents au disque

➡ Ne dessiner que ce qui est nécessaire

➡ Utiliser l'accéléromètre / gyroscope avec autant de parcimonie que Core Location

➡ Limiter les accès réseau

Page 19: Cocoaheads Rennes #3 : Bien coder sur iOS

Le JSON est 52% moins lourd que le XML

Réseau

➡ Choisissez bien votre format !

➡ Exemple avec recherche twitter

0 Ko

5 Ko

10 Ko

14 Ko

19 Ko

Taille de la réponse

9,47 Ko

18,05 Ko

http://search.twitter.com/search.json?q=cocoaheads&result_type=mixed&count=100

Données calculées sur la moyenne de 100 appels à l’API Twitter en JSON vs XML

XML JSON

Page 20: Cocoaheads Rennes #3 : Bien coder sur iOS

Réseau

➡ Ne prendre ce qui est nécessaire

➡ Pourquoi télécharger 100 tweets sur les CocoaHeads alors qu’on en affichera que 15 ?

➡ Astuce: utiliser la pagination

➡ Mais ne pas en abuser: éviter de trop nombreuses petites requêtes

Page 21: Cocoaheads Rennes #3 : Bien coder sur iOS

Réseau

➡ Malheureusement, on n’a pas toujours la main sur la plateforme Web

➡ Il faut s’en accommoder

➡ Commencer la réflexion en partant du mobile dès que possible

Page 22: Cocoaheads Rennes #3 : Bien coder sur iOS

Walter Prévost

« La mémoire, c'est comme une valise. On met toujours dedans des choses qui ne

servent à rien.»

La mémoire

Page 23: Cocoaheads Rennes #3 : Bien coder sur iOS

La mémoire

➡ Objectif: réduire son emprunte mémoire:

➡ Consommer le moins de mémoire, le moins longtemps possible.

Page 24: Cocoaheads Rennes #3 : Bien coder sur iOS

La mémoire

0 Mo

32 Mo

64 Mo

96 Mo

128 Mo

58 Mo

4 Mo10 Mo

12 Mo

32 Mo

12 Mo

Source: Apple TechTalks Paris 2009 Valeurs pour un iPhone 3G

Plus les appareils montent en gamme plus il y a de mémoire.

Cependant, iOS est de plus en plus gourmand avec le temps

Couche graphiqueKernelDémonsSpringboardTéléphoneDisponible

Page 25: Cocoaheads Rennes #3 : Bien coder sur iOS

La mémoire

➡ Principales sources de « gaspillage »:

➡ Les fuites

➡ La mémoire allouée inutilement

➡ La mémoire libérée trop tard

Page 26: Cocoaheads Rennes #3 : Bien coder sur iOS

La mémoire

Rappel: 1 retain / alloc / copy = 1 release

Page 27: Cocoaheads Rennes #3 : Bien coder sur iOS

Gare à l’autoRelease !

➡ Tout objet en autorelease est placé dans le bassin le plus «proche»

➡ Quand le bassin est vidé, il envoie un Release à chacun des objets qu’il gère

L’autorelease très pratique, mais il faut redoubler de vigilance

Page 28: Cocoaheads Rennes #3 : Bien coder sur iOS

Gare à l’autoRelease ! NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; TBXML * tbxml = [[TBXML alloc] initWithXMLData:xmlData]; TBXMLElement *root = tbxml.rootXMLElement; if (root) { TBXMLElement *item = [TBXML childElementNamed:@"item" parentElement:root]; while (item != nil) { // Parsing code item = [TBXML nextSiblingNamed:@"item" searchFromElement:item]; } } [tbxml release]; [pool release];

0MB

13MB

25MB

38MB

50MB

5MB

20MB

35MB

49MB

5MB 5MB 5MB

Parsing d’un fichier XML basé sur le Top 300 iTunes avec TBXML 1.4.Mesures effectuées avec instruments.

Page 29: Cocoaheads Rennes #3 : Bien coder sur iOS

TBXML * tbxml = [[TBXML alloc] initWithXMLData:xmlData]; TBXMLElement *root = tbxml.rootXMLElement; if (root) { TBXMLElement *item = [TBXML childElementNamed:@"item" parentElement:root]; while (item != nil) {

Gare à l’autoRelease !

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Parsing code item = [TBXML nextSiblingNamed:@"item" searchFromElement:item]; } } [tbxml release];

[pool release];

0MB

13MB

25MB

38MB

50MB

5MB 7MB12MB 12MB

5MB 5MB 5MB5MB

20MB

35MB

49MB

5MB 5MB 5MB

Une gestion fine de l’autorelease, c’est une gestion fine de la mémoire

Parsing d’un fichier XML basé sur le Top 300 iTunes avec TBXML 1.4.Mesures effectuées avec instruments.

Page 30: Cocoaheads Rennes #3 : Bien coder sur iOS

Le Dealloc

➡ Un dealloc vide ou incomplet: c’est la garantie de fuites mémoire.

➡ Astuce 1: A la création d’une variable d’instance, on la met de suite dans le dealloc (si il y a lieu).

➡ Astuce 2: Mettre les variable dans le même ordre dans l’interface que dans le dealloc.

➡ Ne jamais oublier le [super dealloc];

Page 31: Cocoaheads Rennes #3 : Bien coder sur iOS

Be lazy

- (IBAction) showCredits:(UIButton*) sender {! [self displayTextPopup:credits_];}- (void) dealloc {! [credits_ release];! [super dealloc];}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self != nil) {

} return self;}

credits_ = [[NSString stringWithContentsOfFile:filePath] retain];

Page 32: Cocoaheads Rennes #3 : Bien coder sur iOS

! ];! [self credits]

Be lazy

- (IBAction) showCredits:(UIButton*) sender {! [self displayTextPopup:}- (void) dealloc {! [credits_ release];! [super dealloc];}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self != nil) {

} return self;}- (NSString*)credits {! if(!credits_) {

! }!! return credits_;}

credits_ = [[NSString stringWithContentsOfFile:filePath] retain];

Page 33: Cocoaheads Rennes #3 : Bien coder sur iOS

Memory warning

➡ Le memory warning signifie que le système va être à court de mémoire.

➡ Soyez courtois, et libérez tout ce que vous pouvez.

➡ Rappelez vous, le système a la License To Kill.

Page 34: Cocoaheads Rennes #3 : Bien coder sur iOS

Memory warning

Trois options pour être tenu au courant:

➡ Dans un ViewController: - (void) didReceiveMemoryWarning;

➡ Dans l’UIApplicationDelegte:

- (void) applicationDidReceiveMemoryWarning:(UIApplication *)application;

➡ Partout ailleurs: UIApplicationDidReceiveMemoryWarningNotification

Page 35: Cocoaheads Rennes #3 : Bien coder sur iOS

Luc Fayard

« Développement : Alliance d'une science inexacte et d'une activité humaine faillible.»

Crash et ralentissement

Page 36: Cocoaheads Rennes #3 : Bien coder sur iOS

Crash et ralentissement

Page 37: Cocoaheads Rennes #3 : Bien coder sur iOS

Core Data

➡ Un NSManagedObjectContext ne peux être partagé entre plusieurs threads

➡ Un NSManagedObject n’est valide que dans son NSManagedObjectContext

➡ Conséquence: il ne faut pas passer de NSManagedObject entre plusieurs threads !

Page 38: Cocoaheads Rennes #3 : Bien coder sur iOS

Core Data

1

3

2

ObjectID

3

ObjectID

Thread 1 / MOC 1 Thread 2 / MOC 2

[monContext objectWithID:monObjectId]; NSString * monObjectId = [monObjet objectID];

Page 39: Cocoaheads Rennes #3 : Bien coder sur iOS

Mais aussi ...

➡ Être très rigoureux sur la gestion des retain / release

➡ User et abuser du respondsToSelector:

➡ Toujours penser aux cas aux limites

➡ Instruments offre des outils pour tracer et comprendre tout ça ...

Page 40: Cocoaheads Rennes #3 : Bien coder sur iOS

Confucius

« L'ouvrier qui veut bien faire son travail doit commencer par aiguiser ses instruments. » 

Analyser

Page 41: Cocoaheads Rennes #3 : Bien coder sur iOS

Analyser

Ce que je voulaisfaire

Ce que je pense avoir fait

Ce que j’ai fait

Page 42: Cocoaheads Rennes #3 : Bien coder sur iOS

Analyser

➡ Analyser, c’est comprendre ce qui a été réellement fait

➡ Instruments est l’outil parfait pour ça:

Consommationmémoire

Fuitesmémoire

Consommationd’énergie

Performances graphiques Zombies

Page 43: Cocoaheads Rennes #3 : Bien coder sur iOS

Jean-Claude Dusse

« Je sens que, ce soir, je vais conclure »

Conclusions

Page 44: Cocoaheads Rennes #3 : Bien coder sur iOS

Conclusions

➡ Bien coder, c’est du temps, de la crédibilité et de l’argent de gagné.

➡ Définir des règles intelligemment ... et s’y tenir !

➡ Soyez courtois avec les ressources

➡ Lisez, creusez et comprenez la documentation ...