Download - CocoaHeads Rennes #1 : Grand Central Dispatch

Transcript
Page 1: CocoaHeads Rennes #1 : Grand Central Dispatch

A la découverte de Grand Central Dispatch

Pierre DuchêneThomas Dupont

Page 2: CocoaHeads Rennes #1 : Grand Central Dispatch

Sommaire

• Blocks➡ Exemples

➡ Syntaxe et utilisation

➡ Gestion mémoire

➡ Bonus

• Grand Central Dispatch➡ Introduction

➡ libdispatch

➡ API haut niveau

Page 3: CocoaHeads Rennes #1 : Grand Central Dispatch

Blocks

Thomas Dupont

Page 4: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 5: CocoaHeads Rennes #1 : Grand Central Dispatch

^(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

Page 6: CocoaHeads Rennes #1 : Grand Central Dispatch

...

- (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

Page 7: CocoaHeads Rennes #1 : Grand Central Dispatch

[UIView animateWithDuration:animations:^{ }completion:^(BOOL finished){ }];[myView removeFromSuperview];

myView.alpha = 0;0.6

Exemples

Page 8: CocoaHeads Rennes #1 : Grand Central Dispatch

selector:@selector(notifReceived:) name: object: ];

...

- (void)notifReceived:(NSNotification*)notif{

}

[[NSNotificationCenter defaultCenter]

Exemples

@"MyNotif" nil

/* doing some stuff */

:selfaddObserver

Page 9: CocoaHeads Rennes #1 : Grand Central Dispatch

[[NSNotificationCenter defaultCenter]queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notif) {

Exemples

@"MyNotif"

/* doing some stuff */

addObserverForName: object:

}];

Page 10: CocoaHeads Rennes #1 : Grand Central Dispatch

Syntaxe et utilisation

^ { NSLog(@"Hello World"); };(void)void

caret

Type de retour

Types des paramètres

Instructions

Page 11: CocoaHeads Rennes #1 : Grand Central Dispatch

Syntaxe et utilisation

^ { NSLog(@"Hello World"); };(void)void

^ { NSLog(@"Hello World"); };(void)

^ { NSLog(@"Hello World"); };

<=>

<=>

Page 12: CocoaHeads Rennes #1 : Grand Central Dispatch

Syntaxe et utilisation

myBlock = ^(int i){ ... };

void ( )(int);^myBlock

void ( )(int);*myFunction

Page 13: CocoaHeads Rennes #1 : Grand Central Dispatch

Syntaxe et utilisation

typedef void (^aBlock)(void);

aBlock (^myBlock)(aBlock);

void (^(^(myBlock)(void (^)(void)))(void);

<=>

Page 14: CocoaHeads Rennes #1 : Grand Central Dispatch

Syntaxe et utilisation

myBlock();

myBlockwithParam(2);

int i = myBlockWithReturn();

Page 15: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 16: CocoaHeads Rennes #1 : Grand Central Dispatch

Syntaxe et utilisation

void (^incrementA)(void) = ^{ a++; };

incrementA();

int a = 3;__block

Référence

Capturer une variable __block garde sa référence

Page 17: CocoaHeads Rennes #1 : Grand Central Dispatch

;

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

Page 18: CocoaHeads Rennes #1 : Grand Central Dispatch

[

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

Page 19: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 20: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 21: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 22: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 23: CocoaHeads Rennes #1 : Grand Central Dispatch

Bonus

@interface BlockAlertView : UIAlertView <UIAlertViewDelegate> {

}

@end

- (void)showWithCompletion:(void (^)(NSInteger index))completion;

void (^completionBlock_)(NSInteger);

Page 24: CocoaHeads Rennes #1 : Grand Central Dispatch

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;

Page 25: CocoaHeads Rennes #1 : Grand Central Dispatch

Grand Central Dispatch

Pierre Duchêne

Page 26: CocoaHeads Rennes #1 : Grand Central Dispatch

Introduction

• Nouveaux éléments de langage (Blocks)

• Une bibliothèque de fonctions (libdispatch)

• Amélioration et simplification de la gestion de la concurrence

Page 27: CocoaHeads Rennes #1 : Grand Central Dispatch

Introduction - Pourquoi GCD

• Complexité du multi-threading

• Multiplication des Cores sur toutes les plateformes

• Mauvaise gestion des ressources

Page 28: CocoaHeads Rennes #1 : Grand Central Dispatch

Introduction - GCD c’est quoi?

• Gestion des threads au niveau du système

• Gestion des problématiques de concurrence (lock, semaphore...)

Page 29: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 30: CocoaHeads Rennes #1 : Grand Central Dispatch

Queues

• Trois types de Queues :

• Main Queue (Main Thread)

• Private Dispatch Queue (exécution série)

• Global Dispatch Queue (exécution parallèle)

Page 31: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 32: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 33: CocoaHeads Rennes #1 : Grand Central Dispatch

Queues

• Deux types d’exécution:

• Synchrone

• Asynchrone

Page 34: CocoaHeads Rennes #1 : Grand Central Dispatch

libdispatch - import

• Comment utiliser libdispatch dans son projet?

#import <dispatch/dispatch.h>

Page 35: CocoaHeads Rennes #1 : Grand Central Dispatch

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 ?

Page 36: CocoaHeads Rennes #1 : Grand Central Dispatch

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);

Page 37: CocoaHeads Rennes #1 : Grand Central Dispatch

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];});

Page 38: CocoaHeads Rennes #1 : Grand Central Dispatch

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];}

Page 39: CocoaHeads Rennes #1 : Grand Central Dispatch

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

Page 40: CocoaHeads Rennes #1 : Grand Central Dispatch

libdispatch - deadlock

• Attention aux deadlock

dispatch_sync(queue, ^{ // Some code! dispatch_sync(queue, ^{ // Another block });});

Block 2

Private queue Other Thread

Block 1

!

Page 41: CocoaHeads Rennes #1 : Grand Central Dispatch

API haut niveau

• Grand Central Dispatch ajoute à l’existant

• NSOperation

• NSOperationQueue

Page 42: CocoaHeads Rennes #1 : Grand Central Dispatch

API haut niveau

• NSBlockOperation

• Classe concrête de NSOperation

• Gère l’exécution en parallèle de un ou plusieurs Blocks

Page 43: CocoaHeads Rennes #1 : Grand Central Dispatch

API haut niveau

• NSOperationQueue

• C’est elle qui gère l’exécution des opérations

• Peut être configurée

Page 44: CocoaHeads Rennes #1 : Grand Central Dispatch

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 :

Page 45: CocoaHeads Rennes #1 : Grand Central Dispatch

API haut niveau - dépendance

NSBlockOperation* op1 = ...:NSBlockOperation* op2 = ...:

[op2 addDependencie:op1];

• Comment indiquer des dépendances entre opérations?

Page 46: CocoaHeads Rennes #1 : Grand Central Dispatch

API haut niveau - iOS

Sur iOS les NSOperationQueue n’utilisent pas Grand Central Dispatch!