La syntaxe de bloc dans Objective C (et même C, je présume) est notoirement incongrue. Passer des blocs en tant qu'arguments est différent de la déclaration de blocs en tant qu'ivars, ce qui est différent de celui de typedef
ing.
Existe-t-il une liste complète de syntaxe de déclaration de bloc que je pourrais garder sous la main pour une référence rapide?
Tout au long, laisser
return_type
soit le type d'objet/primitive/etc. vous souhaitez retourner (généralement void
)blockName
être le nom de la variable du bloc que vous créezvar_type
soit le type objet/primitive/etc. vous souhaitez passer en argument (laissez vide pour aucun paramètre)varName
soit le nom de la variable du paramètre donnéEt rappelez-vous que vous pouvez créer autant de paramètres que vous le souhaitez.
Peut-être le plus commun pour de la déclaration.
return_type (^blockName)(var_type) = ^return_type (var_type varName)
{
// ...
};
Cela ressemble beaucoup à la déclaration de blocs en tant que variables, même si elles sont légèrement différentes.
@property (copy) return_type (^blockName) (var_type);
Notez que ceci est distinct de "Blocks as Arguments"; dans ce cas, vous déclarez une méthode qui veut un argument de bloc.
- (void)yourMethod:(return_type (^)(var_type))blockName;
Notez que ceci est distinct de "Blocks as Parameters"; dans ce cas, vous appelez une méthode qui souhaite un argument de bloc avec un bloc anonyme. Si vous avez déjà déclaré une variable de bloc, il suffit de passer le nom de la variable en tant qu'argument.
[someObject doSomethingWithBlock: ^return_type (var_type varName)
{
//...
}];
Il s'agit fonctionnellement d'un bloc anonyme. Cependant, la syntaxe pour affecter des blocs aux variables consiste simplement à définir la variable sur un bloc anonyme.
^return_type (var_type varName)
{
//...
};
typedef
BlockCela vous permet de définir un nom abrégé pouvant être référencé comme tout autre nom de classe lors de la déclaration de blocs.
typedef return_type (^blockName)(var_type);
Pour utiliser ensuite plus tard blockName
à la place de la syntaxe de déclaration de bloc standard, remplacez simplement.
Ceci est sans doute une utilisation moins utile des blocs, mais peut néanmoins avoir sa place. Un bloc en ligne est un bloc anonyme appelé immédiatement après l'instanciation.
^return_type (var_type varName)
{
//...
}(var);
Les blocs en ligne sont principalement utiles pour la compensation de périmètre et sont à peu près équivalents à de simples morceaux de code délimités par des accolades.
{
//...
}
Cela vous permet d'appeler un bloc depuis lui-même, créant ainsi une boucle pouvant être utilisée lors des rappels et des appels GCD. Cette méthode d'instanciation est libre de cycles de conservation dans ARC.
__block return_type (^blockName)(var_type) = [^return_type (var_type varName)
{
if (returnCondition)
{
blockName = nil;
return;
}
// ...
} copy];
blockName(varValue);
Une méthode peut retourner un bloc,
- (return_type(^)(var_type))methodName
{
// ...
}
comme peut le faire une fonction, même si c'est un peu étrange.
return_type (^FunctionName())(var_type)
{
// ...
}
Si j'ai oublié quelque chose, merci de me le faire savoir dans les commentaires et je les rechercherai/les ajouterai.
blockName = (varName: var_type) -> (return_type)
C'est presque comme si c'était une fonctionnalité linguistique.
Personnellement, j'aime utiliser ce site Web ( http://fuckingblocksyntax.com ). Le nom est plus facile à retenir que la syntaxe de bloc elle-même:
et si vous ne pouvez pas charger les URL contenant des mots incorrects, vous pouvez utiliser ce miroir: http://goshdarnblocksyntax.com
Typedef:
typedef void (^block)(NSString *arg);
En ligne:
void (^block)(NSString *) = ^(NSString *param) {
// do something....
};
Méthode:
- (void)method:(void (^)(NSString *param))handler
La bibliothèque de fragments Xcode 4 contient des modèles de variables de type et de blocs en ligne. Ils sont également disponibles en complétion automatique (typedefblock
et inlineblock
).
Pour les blocs en tant qu'arguments aux méthodes, je vous conseillerais de déclarer un typedef
et de l'utiliser simplement. Cela rend le code beaucoup plus facile à lire.
J'ai écrit pour la classe d'achèvement un verrou qui retournera les valeurs d'un dé après leur agitation:
Définir typedef avec returnType (.h
au-dessus de @interface
déclaration)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Définir un @property
pour le bloc (.h
)
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
Définir une méthode avec finishBlock
(.h
)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Insérer la méthode précédemment définie dans le fichier .m
et valider finishBlock
dans @property
défini avant
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
Pour déclencher completionBlock
, passez-y le type de variable prédéfini (n'oubliez pas de vérifier si le completionBlock
existe)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
typedef void (^OkBtnBlock)(id data);
typedef void (^CancelBtnBlock)();
@property (nonatomic, strong) OkBtnBlock okBtnBlock;
@property (nonatomic, strong) CancelBtnBlock cancelBtnBlock;
+ (void)foo:(OkBtnBlock)okBtn andCancel:(CancelBtnBlock)btnCancel;
Si vous avez besoin de travailler dans Xcode 4.2, vous pouvez également @ synthétiser un bloc déclaré en tant que propriété, comme vous le feriez avec une propriété non bloquante. Ne laissez pas la syntaxe de bloc vous jeter.
Si votre propriété de bloc est la suivante:
@property (copy) return_type (^blockName) (var_type);
Ensuite, votre @ synthèse est la suivante:
@property blockName;
À votre santé.