cocoaheads rennes #1 : grand central dispatch
DESCRIPTION
Slides de la présentation "TA la découverte de Grand Central Dispatch" de la session des CocoaHeads Rennais du 21 avril 2011. Présentation assurée par Pierre Duchêne et Thomas Dupont, ingénieurs chez NijiTRANSCRIPT
A la découverte de Grand Central Dispatch
Pierre DuchêneThomas Dupont
Sommaire
• Blocks➡ Exemples
➡ Syntaxe et utilisation
➡ Gestion mémoire
➡ Bonus
• Grand Central Dispatch➡ Introduction
➡ libdispatch
➡ API haut niveau
Blocks
Thomas Dupont
sortedArrayUsingFunction:intSort context:NULL];
...
NSInteger intSort(id obj1, id obj2, void* context){
int v1 = [obj1 intValue];int v2 = [obj2 intValue];
if (v1 < v2)return NSOrderedAscending;
else if (v1 > v2)return NSOrderedDescending;
elsereturn NSOrderedSame;
}
NSArray* sortedArray = [myArray
int v1 = [obj1 intValue];int v2 = [obj2 intValue];
if (v1 < v2)return NSOrderedAscending;
else if (v1 > v2)return NSOrderedDescending;
elsereturn NSOrderedSame;
Exemples
^(id obj1, id obj2) {
NSArray* sortedArray = [myArray sortedArrayUsingComparator:
int v1 = [obj1 intValue];int v2 = [obj2 intValue];
if (v1 < v2)return NSOrderedAscending;
else if (v1 > v2)return NSOrderedDescending;
elsereturn NSOrderedSame;
}];
Exemples
...
- (void)fadeAnimationDidStop:(NSString*)animId finished:(NSNumber*)finished context:(void*)context
{
}
[UIView beginAnimations:@"" context:nil];[UIView setAnimationDuration: ];[UIView setAnimationDelegate:self];[UIView setAnimationDidStopSelector:
@selector(fadeAnimationDidStop:finished:context:)];
[UIView commitAnimations];
[myView removeFromSuperview];
myView.alpha = 0;
0.6
Exemples
[UIView animateWithDuration:animations:^{ }completion:^(BOOL finished){ }];[myView removeFromSuperview];
myView.alpha = 0;0.6
Exemples
selector:@selector(notifReceived:) name: object: ];
...
- (void)notifReceived:(NSNotification*)notif{
}
[[NSNotificationCenter defaultCenter]
Exemples
@"MyNotif" nil
/* doing some stuff */
:selfaddObserver
[[NSNotificationCenter defaultCenter]queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notif) {
Exemples
@"MyNotif"
/* doing some stuff */
addObserverForName: object:
}];
Syntaxe et utilisation
^ { NSLog(@"Hello World"); };(void)void
caret
Type de retour
Types des paramètres
Instructions
Syntaxe et utilisation
^ { NSLog(@"Hello World"); };(void)void
^ { NSLog(@"Hello World"); };(void)
^ { NSLog(@"Hello World"); };
<=>
<=>
Syntaxe et utilisation
myBlock = ^(int i){ ... };
void ( )(int);^myBlock
void ( )(int);*myFunction
Syntaxe et utilisation
typedef void (^aBlock)(void);
aBlock (^myBlock)(aBlock);
void (^(^(myBlock)(void (^)(void)))(void);
<=>
Syntaxe et utilisation
myBlock();
myBlockwithParam(2);
int i = myBlockWithReturn();
Copie constante
Syntaxe et utilisation
float newAlpha = 1;
[UIView animateWithDuration:0.5 delay:1 options:0animations:^{ myView.alpha = newAlpha; }completion:NULL];
newAlpha = 0;
Capturer une variable en fait une copie constante
Syntaxe et utilisation
void (^incrementA)(void) = ^{ a++; };
incrementA();
int a = 3;__block
Référence
Capturer une variable __block garde sa référence
;
Gestion mémoire
typedef void (^Block)(void);
Block block;
if ( ... ) {block =
if ( ... ) {
} else {
}
} else {block =
}
block();
int* pInt;
int a = 1;pInt = &a;
int b = 1;pInt = &b;
// utilisation de pInt
;^{ ... }
^{ ... }
Un Block est créé sur la pile et non sur le tas !
<=>
Wrong
[
Gestion mémoire
typedef void (^Block)(void);
Block block;
if ( ... ) {block =
} else {block =
}
block();
copy] ;^{ ... }[ autorelease]
Copier un Block sur la pile le déplace sur le tas !
[ copy] ;^{ ... }[ autorelease]
Right
myObject = [[MyObject alloc] initWithBlock:^{NSLog(@"%i",
}];
Gestion mémoire
MyObject* myObject;int myIvar;
myIvar);
MyClass.h
MyClass.mself
myObject
Block
Capturer un objet le retient !Capturer une variable d’instance retient l’objet auquel elle appartient !
retain cycle
Wrong
myObject = [[MyObject alloc] initWithBlock:^{NSLog(@"%i",
}];
Gestion mémoire
MyObject* myObject;int myIvar;
MyClass* selfBlock = self;
selfBlock-> myIvar);
MyClass.h
MyClass.m
__block
Capturer un objet __block ne le retient pas !
Right
v.transform = CGAffineTransformMakeScale(0.7, 0.7);v.alpha = 0;[self.view addSubview:v];
[UIView animateWithDuration:0.2 animations:^{
} completion:^(BOOL finished) {
}];
Bonus
[UIView animateWithDuration:0.15 animations:^{
} completion:^(BOOL finished) {
}];
v.transform = CGAffineTransformMakeScale(1.25, 1.25);v.alpha = 0.6;
[UIView animateWithDuration:0.1 animations:^{
} completion:NULL];v.transform = CGAffineTransformIdentity;
v.transform = CGAffineTransformMake(0.85, 0.85);v.alpha = 1;
Effet Bounce des UIAlertView
Bonus
[alert showWithCompletion:^(NSInteger index) {
}];
UIAlertView* alert = [[UIAlertView alloc] init... delegate: ...];
if (index == 1) {[UIApplication openURL:myURL];
}
[alert release];
nil
N’existe pas!Codons le
Bonus
@interface BlockAlertView : UIAlertView <UIAlertViewDelegate> {
}
@end
- (void)showWithCompletion:(void (^)(NSInteger index))completion;
void (^completionBlock_)(NSInteger);
Bonus@implementation BlockAlertView
@end
- (void)showWithCompletion:(void (^)(NSInteger index))completion{
}
- (void)alertView:(UIAlertView*)alert clickedButtonAtIndex:(NSInteger)index{
}
completionBlock_ = [completion copy];self.delegate = self;[self show];
completionBlock_(index);[completionBlock_ release];completionBlock_ = nil;
- (void)alertViewCancel:(UIAlertView*)alert{
}
completionBlock_(-1);[completionBlock_ release];completionBlock_ = nil;
Grand Central Dispatch
Pierre Duchêne
Introduction
• Nouveaux éléments de langage (Blocks)
• Une bibliothèque de fonctions (libdispatch)
• Amélioration et simplification de la gestion de la concurrence
Introduction - Pourquoi GCD
• Complexité du multi-threading
• Multiplication des Cores sur toutes les plateformes
• Mauvaise gestion des ressources
Introduction - GCD c’est quoi?
• Gestion des threads au niveau du système
• Gestion des problématiques de concurrence (lock, semaphore...)
libdispatch - Queues
• Liste FIFO de Blocks à exécuter
• Ajout de Block FIFO
• Lancement de l’exécution d’un Block FIFO
• Gère les threads qui exécutent les Blocks
Queues
• Trois types de Queues :
• Main Queue (Main Thread)
• Private Dispatch Queue (exécution série)
• Global Dispatch Queue (exécution parallèle)
Block 3
Private Dispatch QueueCurrent Thread
Block 2
Private queue Other Thread
Block 1
Ajoute Block 1 puis Block 2 puis Block 3 Exécute Block 1
puis Block 2 puis Block 3
Block 3
Global Dispatch QueueCurrent Thread
Block 2
Global queue Thread Auto Thread Auto
Block 1
Ajoute Block 1 puis Block 2 puis Block 3
Lance Block 1
puis Block 2
Puis Block 3 surle premier threadqui sera libéré
potentiellementavant la findu Block 1
Queues
• Deux types d’exécution:
• Synchrone
• Asynchrone
libdispatch - import
• Comment utiliser libdispatch dans son projet?
#import <dispatch/dispatch.h>
libdispatch - queue
dispatch_queue_t main_queue;dispatch_queue_t serial_queue;dispatch_queue_t global_queue;
// main queuemain_queue = dispatch_get_main_queue();
// private dispatch queue serial_queue = dispatch_queue_create("com.example.myQueue", NULL);
// global dispath queueglobal_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_release(serial_queue);
• Comment créer une queue ?
libdispatch - étude de cas
• Process en background + mise à jour de l’UI
dispatch_queue_t background_queue;dispatch_queue_t main_queue;
backgroung_queue = dispatch_queue_create("com.example.myQueue", NULL);main_queue = dispatch_get_main_queue();
dispatch_async(background_queue, ^{ int result = hardWorkInBackground(); dispatch_async(main_queue, ^{ updateUIWithData(result); });});
dispatch_release(background_queue);
libdispatch - étude de cas
• Traitement sur les éléments d’un tableau
dispatch_queue_t global_queue;global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSArray* mySudokuGrid = ...;
dispatch_apply(nb_iteration,global_queue,^(size_t index){ MyCell* cell = [mySudokuGrid objectAtIndex:index]; [cell computeSolutions];});
libdispatch - étude de cas
• Comment remplacer les locks ?
- (void)updateImageCacheWithImage:(UIImage*)img { NSLock* l = self.cacheLock; [l lock]; // Section critique, ne pas ajouter deux fois la même image! if ([self.imageCache containsObj:img]) { [l unlock]; // Surtout ne pas oublier! return; } [self.imageCache addObj:img]; [l unlock];}
libdispatch - étude de cas
• Simplement par une Queue!
- (void)updateImageCacheWithImage:(UIImage*)img {
dispatch_sync(serial_queue,^{ // Section critique, ne pas ajouter deux fois la même image! if ([self.imageCache containsObj:img]) { return; } [self.imageCache addObj:img]; });}
ou mieux : dispatch_async
libdispatch - deadlock
• Attention aux deadlock
dispatch_sync(queue, ^{ // Some code! dispatch_sync(queue, ^{ // Another block });});
Block 2
Private queue Other Thread
Block 1
!
API haut niveau
• Grand Central Dispatch ajoute à l’existant
• NSOperation
• NSOperationQueue
API haut niveau
• NSBlockOperation
• Classe concrête de NSOperation
• Gère l’exécution en parallèle de un ou plusieurs Blocks
API haut niveau
• NSOperationQueue
• C’est elle qui gère l’exécution des opérations
• Peut être configurée
API haut niveau - base
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];NSBlockOperation* blockOp = [NSBlockOperation blockOperationWithBlock:^{
// Some Code}];
[aQueue addOperation:blockOp];...[aQueue addOperationWithBlock:^{ // Another Block }];...[aQueue release];
• Créer et lancer une opération via NSOperationQueue :
API haut niveau - dépendance
NSBlockOperation* op1 = ...:NSBlockOperation* op2 = ...:
[op2 addDependencie:op1];
• Comment indiquer des dépendances entre opérations?
API haut niveau - iOS
Sur iOS les NSOperationQueue n’utilisent pas Grand Central Dispatch!
http://developer.apple.com
http://thirdcog.eu/pwcblocks/
Références
Contacts
Partenaire
CocoaHeads #1
Traduction automatique et intelligente d’applications Cocoa
Mail : [email protected] : [email protected] : www.niji.fr
A la découverte de Grand Central Dispatch
Mail : [email protected] : www.foodreporter.frGitHub : github.com/AliSoftware
http://cocoaheads.fr