2011-01-06 17 views
11

Estoy tratando de entender cómo usar bloques en iOS. He leído los documentos de Apple pero, como de costumbre, son vagos e incompletos y no se mencionan varios datos esenciales. También he buscado en Google sin éxito. Esto es lo que trato de hacer como ejercicio para comprender eso.Intentando comprender bloques en iOS

He creado un bloque para leer una cadena y comparar la cadena con la lectura anterior. Si las cadenas no son iguales, devuelva SÍ, si son iguales, devuelva NO.

Esta es la forma en que lo hice:

I declaró esto en .h

BOOL (^differentStrings)(void); 

declaré esto en .m, dentro viewDidLoad en 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; 
    } 
}; 

Éste es cómo uso: Tengo un hilo que hace esto:

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

Estos son los problemas que tengo:

  1. el bloque siempre vuelven Sí (cadenas son diferentes)
  2. No me siento cómodo declarar esta videDidLoad interior. ¿Cómo debo declarar esto, para poder usarlo globalmente como método? ¿Debería poner esto como lo haría con un método?
  3. Estoy llamando a un método "getString" dentro del bloque. ¿Está bien?
  4. Me resulta extraño declarar las variables de bloque en .m. Como veo, debo declarar las variables de bloque en .h y luego simplemente usarlas en .m. Intenté hacer eso, pero recibí un error.
  5. He configurado un punto de depuración en la primera línea del bloque, pero no se detiene allí;
  6. NSlog línea dentro del bloque no imprime nada. ¿No se llama al bloque?

¿Pueden ayudarme con esto?

Respuesta

15

No está entendiendo cómo funcionan los bloques. (Bueno, eso es un poco obvio.) De la misma manera que previousString es una variable que apunta a un NSString, differentStrings es una variable que apunta a un bloque. No es el resultado de ejecutar el bloque, sino el bloque en sí. Es decir, después de hacer esto:

__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 es una variable apuntando al bloque .Así, cuando se hace esto:

if (differentStrings) 

... simplemente está comprobando si contiene algo differentStrings distinto de 0 o NULO. Como contiene un bloque, no está vacío, por lo que se evalúa como verdadero.

Recuerde: differentStrings es una variable de bloque, no una variable BOOL. Contiene un bloque (una función, si se quiere), que cuando llamado devolverá un bool. Por lo tanto, para ejecutar realmente el bloque, debe llamarlo. De esta manera:

differentStrings(); 

o, en su caso:

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

Editar: Como se señaló en los comentarios, ya que differentStrings es una variable de instancia, es necesario copy que, al igual que lo Llamaría al retain en cualquier otro objeto asignado a una variable de instancia. (Por razones técnicas no entraré ahora, siempre debe usar copy con bloques en lugar de retain). Igualmente, deberá llamar al release en algún momento posterior, quizás en su método dealloc.

+1

Creo que también necesitarás 'copiar' el bloque cuando lo asignes al ivar. De lo contrario, el bloque sale del alcance al salir de 'viewDidLoad'. Además, si 'previousString' necesita ser una variable' __block', 'currentString' puede ser una variable local de bloque. –

+1

Absolutamente correcto. He actualizado mi respuesta. –

+0

gracias por la respuesta. He agregado el paréntesis cuando llamé al bloque y también hice un Block_copy (differentStrings) después de crearlo en viewDidLoad pero se cuelga cuando llamo al bloque usando differentStrings() ...Intenté llamar al bloque desde el mismo ámbito y funciona, pero cuando lo llamo desde un ámbito diferente, se bloquea, incluso con Block_copy. – SpaceDog

3

no pude conseguir mi cabeza alrededor de los bloques hasta que vi Block y Mulithreading de Stanfords Developing Apps for iOS

+0

gracias, que el vídeo ayudó a entender más profundamente, pero incluso después de ver que aún tengo las mismas preguntas, que no se abordan en esta clase. – SpaceDog

4

no creo que en realidad estás ejecutar el bloque. Creo que su código debe ser

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

Tratar un bloque como una función. Creo que solo estabas revisando para ver si el bloque había sido definido, no ejecutándolo.

Además, si no necesita acceder a un NSString fuera del bloque, puede deshacerse del calificador __block y mover la declaración currentString dentro del bloque.

Si necesita otro recurso en bloques, los cubro en la sesión de otoño de mi curso avanzado de desarrollo de iOS on iTunes U. Describo la sintaxis de bloque en la sesión Understanding Cocoa y su uso en Grand Central Dispatch dentro de la sesión de subprocesamiento múltiple. Las notas del curso también tienen enlaces a algunas aplicaciones de muestra que usan bloques de diferentes maneras.

Tampoco puedo recomendar lo suficiente que vea las sesiones de video WWDC 2010 206 - Introducing Blocks y Grand Central Dispatch en iPhone y 211 - Simplifying iPhone App Development con Grand Central Dispatch.

+0

'previousString' necesita ser una variable' __block' porque su valor se referencia entre invocaciones posteriores del bloque. Además, el bloque debe copiarse al asignar al ivar o saldrá del alcance. –

+1

@Daniel - Buen punto, malinterpreté cómo estaba usando esa cadena. –

+0

Gracias Brad, lo comprobaré. – SpaceDog

Cuestiones relacionadas