Top Banner
A la découverte de Grand Central Dispatch Pierre Duchêne Thomas Dupont
48

CocoaHeads Rennes #1 : Grand Central Dispatch

May 15, 2015

Download

Technology

CocoaHeadsRNS

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
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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!