CocoaHeads Rennes #1 : Grand Central Dispatch

Post on 15-May-2015

1.931 views 1 download

Tags:

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 Niji

Transcript of CocoaHeads Rennes #1 : Grand Central Dispatch

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

pierre.duchene@niji.fr

thomas.dupont@niji.fr

Partenaire

julien@cocoaheads.fr

thomas.dupont@cocoaheads.fr

CocoaHeads #1

Traduction automatique et intelligente d’applications Cocoa

Mail : thomas.dupont@niji.frMail : pierre.duchene@niji.frWeb : www.niji.fr

A la découverte de Grand Central Dispatch

Mail : olivier@foodreporter.netWeb : www.foodreporter.frGitHub : github.com/AliSoftware

http://cocoaheads.fr