2011-01-06 3 views
11

J'essaie de comprendre comment utiliser les blocs sur iOS. J'ai lu les documents d'Apple mais, comme d'habitude, ils sont vagues et incomplets et plusieurs informations essentielles ne sont pas mentionnées. J'ai aussi googlé sans succès. C'est ce que j'essaie de faire pour comprendre cela.Essayer de comprendre les blocs sur iOS

J'ai créé un bloc pour lire une chaîne et comparer la chaîne à la lecture précédente. Si les chaînes ne sont pas identiques, renvoyez YES, si elles sont identiques, renvoyez NO.

Voilà comment je l'ai fait:

Je déclare ceci sur .h

BOOL (^differentStrings)(void); 

Je déclarais cela sur .m, à l'intérieur viewDidLoad dans un viewController

__block NSString * previousString; 
__block NSString * currentString; 
differentStrings = ^(void){ 

    currentString = [self getString]; 
    NSLog(@"%@", currentString); // not printing anything on console 

    if (![currentString isEqualToString:previousString]) { 
     previousString = currentString; 
     return YES; 
    } else { 
     return NO; 
    } 
}; 

Voilà comment je utiliser: J'ai un fil qui fait ceci:

if (differentStrings) 
    NSLog (@"strings are different); 

Ce sont les problèmes que j'ai:

  1. le bloc reviennent toujours OUI (chaînes sont différentes)
  2. Je ne suis pas à l'aise de déclarer ceci à l'intérieur videDidLoad. Comment dois-je déclarer ceci, afin que je puisse l'utiliser globalement comme une méthode? Dois-je mettre cela comme je le ferais avec une méthode?
  3. J'appelle une méthode "getString" à l'intérieur du bloc. Est-ce que c'est bon?
  4. Je trouve étrange de déclarer les variables de bloc sur .m. Comme je le vois, je devrais déclarer les variables de bloc sur .h et ensuite les utiliser sur .m. J'ai essayé de le faire, mais j'ai reçu une erreur.
  5. J'ai mis en place un point de débogage sur la première ligne du bloc mais il ne s'arrête pas là;
  6. La ligne NSlog à l'intérieur du bloc n'imprime rien. Le bloc n'est-il pas appelé?

Pouvez-vous m'aider avec ça?

Répondre

15

Vous vous méprenez sur le fonctionnement des blocs. (D'accord, donc c'est un peu évident.) De la même manière que previousString est une variable pointant vers un NSString, differentStrings est une variable pointant vers un bloc. Pas le résultat de l'exécution du bloc, mais plutôt, le bloc lui-même. Autrement dit, une fois que vous faites cela:

__block NSString * previousString; 
__block NSString * currentString; 
differentStrings = ^(void){ 

    currentString = [self getString]; 
    NSLog(@"%@", currentString); // not printing anything on console 

    if (![currentString isEqualToString:previousString]) { 
     previousString = currentString; 
     return YES; 
    } else { 
     return NO; 
    } 
}; 

differentStrings est une variable pointant au bloc .Ainsi, quand vous faites ceci:

if (differentStrings) 

... vous vérifiez simplement si differentStrings contient quelque chose autre que 0 ou NULL. Comme il contient un bloc, il n'est pas vide, donc il est évalué à true. N'oubliez pas: differentStrings est une variable de bloc, pas une variable BOOL. Il contient un bloc (une fonction, si vous voulez), qui quand appelé retournera un bool. Ainsi, afin de réellement exécuter le bloc, vous devez l'appeler. Comme ceci:

differentStrings(); 

ou, dans votre cas:

if (differentStrings()) { 
    NSLog (@"strings are different"); 
} 

Edit: Comme indiqué dans les commentaires, puisque differentStrings est une variable d'instance, vous devez copy, tout comme vous appelez retain sur tout autre objet affecté à une variable d'instance. (Pour des raisons techniques, je ne vais pas entrer maintenant, vous devriez toujours utiliser copy avec des blocs au lieu de retain.) De même, vous devrez appeler release à un moment donné, peut-être dans votre méthode dealloc.

+1

Je pense que vous auriez aussi besoin de "copier" le bloc lors de l'attribution à l'ivar. Sinon, le bloc sort de la portée en quittant 'viewDidLoad'. De même, alors que 'previousString' doit être une variable' __block', 'currentString' peut être une variable locale. –

+1

Tout à fait raison. J'ai mis à jour ma réponse. –

+0

merci pour la réponse. J'ai ajouté la parenthèse quand j'ai appelé le bloc et ai également fait un Block_copy (differentStrings) après l'avoir créé sur viewDidLoad mais il se bloque quand j'appelle le bloc using differentStrings() ...J'ai essayé d'appeler le bloc de la même portée et cela fonctionne mais quand je l'appelle d'une portée différente, il se bloque, même avec le Block_copy. – SpaceDog

3

Je ne pouvais pas obtenir ma tête autour des blocs jusqu'à ce que je voyais Block et Mulithreading de Stanfords Developing Apps for iOS

+0

grâce, cette vidéo a aidé à comprendre plus profondément, mais même après avoir regardé que j'ai toujours les mêmes questions, pas aussi abordé par cette classe. – SpaceDog

4

Je ne crois pas que vous exécuter réellement le bloc. Je pense que votre code doit être

if (differentStrings()) 
{ 
    NSLog (@"strings are different); 
} 

Traitez un bloc comme une fonction. Je pense que vous étiez en train de vérifier si le bloc avait été défini et non exécuté. De plus, si vous n'avez pas besoin d'accéder à un NSString en dehors du bloc, vous pouvez vous débarrasser du qualificateur __block et déplacer la déclaration currentString à l'intérieur du bloc.

Si vous avez besoin d'une autre ressource sur des blocs, je les couvre dans la session d'automne de mon cours avancé de développement iOS on iTunes U. Je décris la syntaxe des blocs dans la session Understanding Cocoa, et leur utilisation dans Grand Central Dispatch au sein de la session multithreading. Les notes de cours contiennent également des liens vers des exemples d'applications utilisant des blocs de différentes manières.Je ne peux pas recommander assez fortement que vous regardiez les sessions vidéo WWDC 2010 206 - Présentation des blocs et Grand Central Dispatch sur iPhone et 211 - Simplification du développement d'applications iPhone avec Grand Central Dispatch.

+0

'previousString' doit être une variable' __block' car sa valeur est référencée entre les invocations suivantes du bloc. En outre, le bloc doit être copié lors de l'attribution à l'ivar ou il sortira hors de la portée. –

+1

@Daniel - Bon point, j'aurais mal lu comment il utilisait cette chaîne. –

+0

Merci Brad, je vais vérifier. – SpaceDog