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
Recommended