2011-10-29 17 views
129

¿Cómo puedo pasar un Block a un Function/Method?Bloque de paso Objective-C como parámetro

Probé - (void)someFunc:(__Block)someBlock pero no sirvió.

es decir. ¿Cuál es el tipo para un Block?

+6

Una referencia que utilizo más de lo que importa a admitir: http: // goshdarnblocksyntax. com/ – oltman

+0

http://fuckingblocksyntax.com/ :) – aryaxt

Respuesta

236

El tipo de bloque varía según sus argumentos y su tipo de retorno. En el caso general, los tipos de bloque se declaran de la misma manera que los tipos de puntero a función, pero reemplazando el * con un ^. Una forma de pasar un bloque a un método es la siguiente:

- (void)iterateWidgets:(void (^)(id, int))iteratorBlock; 

Pero como pueden ver, es complicado. en su lugar se puede utilizar un typedef para hacer tipos de bloques más limpio:

typedef void (^ IteratorBlock)(id, int); 

y luego pasar ese bloque a un método de este modo:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock; 
+0

¿Por qué estás pasando id como argumento? ¿No es posible pasar fácilmente un NSNumber por ejemplo? ¿Cómo se vería eso? – bas

+7

Definitivamente puede pasar un argumento fuertemente tipado como 'NSNumber *' o 'std :: string &' o cualquier otra cosa que pueda pasar como un argumento de función. Esto es solo un ejemplo. (Para un bloque que es equivalente excepto para reemplazar 'id' con' NSNumber', 'typedef' sería' typedef void (^ IteratorWithNumberBlock) (NSNumber *, int); '.) –

+0

Esto muestra la declaración del método. Un problema con los bloques es que el estilo de declaración "desordenado" no hace que sea claro y fácil escribir la llamada al método real con un argumento de bloque real. – uchuugaka

49

Esto podría ser útil:

- (void)someFunc:(void(^)(void))someBlock; 
+0

falta un paréntesis – newacct

+0

Este me funcionó mientras que el anterior no. Por cierto, amigo, eso fue, de hecho, útil. – tanou

6

También puede configurar como un simple bloque de la propiedad si es aplicable para usted:

@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString); 

asegúrese de que la propiedad de bloque es "copia"!

y por supuesto también se puede utilizar typedef:

typedef void (^SimpleBlock)(id); 

@property (nonatomic, copy) SimpleBlock someActionHandler; 
22

usted puede hacer como este, pasando de bloques como un parámetro de bloque:

//creating a block named "completion" that will take no arguments and will return void 
void(^completion)() = ^() { 
    NSLog(@"bbb"); 
}; 

//creating a block namd "block" that will take a block as argument and will return void 
void(^block)(void(^completion)()) = ^(void(^completion)()) { 
    NSLog(@"aaa"); 
    completion(); 
}; 

//invoking block "block" with block "completion" as argument 
block(completion); 
+2

esta respuesta realmente podría hacer con alguna explicación ... – katzenhut

+0

Hm, estás pasando el segundo bloque como el parámetro al primero. Eso es todo. –

+2

Sí, podría haber sido más claro, también. sugerí una edición para explicar a qué me refiero. – katzenhut

7

una forma más de pasar bloque usando funciones с en ejemplo a continuación. He creado funciones para realizar cualquier cosa en el fondo y en la cola principal.

archivo blocks.h

void performInBackground(void(^block)(void)); 
void performOnMainQueue(void(^block)(void)); 

archivo blocks.m

#import "blocks.h" 

void performInBackground(void(^block)(void)) { 
    if (nil == block) { 
     return; 
    } 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block); 
} 

void performOnMainQueue(void(^block)(void)) { 
    if (nil == block) { 
     return; 
    } 

    dispatch_async(dispatch_get_main_queue(), block); 
} 

Que blocks.h importación cuando sea necesario y invocarlo:

- (void)loadInBackground { 

    performInBackground(^{ 

     NSLog(@"Loading something in background"); 
     //loading code 

     performOnMainQueue(^{ 
      //completion hadler code on main queue 
     }); 
    }); 
} 
2

A pesar de las respuestas dadas en este Hilo, realmente tuve problemas para escribir una función que tomara un Bloque como función, y con un parámetro. Eventualmente, aquí está la solución que se me ocurrió.

que quería escribir una función genérica, loadJSONthread, lo que llevaría la URL de un servicio web JSON, cargar algunos datos JSON de esta URL en un subproceso de fondo, a continuación, devolver un NSArray * de los resultados de vuelta a la función de llamada.

Básicamente, quería mantener oculta toda la complejidad del hilo de fondo en una función reutilizable genérica.

Así es como me gustaría llamar a esta función:

NSString* WebServiceURL = @"http://www.inorthwind.com/Service1.svc/getAllCustomers"; 

[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) { 

    // Finished loading the JSON data 
    NSLog(@"Loaded %lu rows.", (unsigned long)results.count); 

    // Iterate through our array of Company records, and create/update the records in our SQLite database 
    for (NSDictionary *oneCompany in results) 
    { 
     // Do something with this Company record (eg store it in our SQLite database) 
    } 

} ]; 

... y este es el bit luché con: cómo declarar, y cómo conseguir que se llame a la función Bloquear vez que los datos se cargado, y pasar el Block un NSArray * registros de carga:

+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData 
{ 
    __block NSArray* results = nil; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue, ^{ 

     // Call an external function to load the JSON data 
     NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString]; 
     results = [dictionary objectForKey:@"Results"]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      // This code gets run on the main thread when the JSON has loaded 
      onLoadedData(results); 

     }); 
    }); 
} 

Este StackOverflow cuestión se refiere a cómo llaman funciones, pasando de un bloque como un parámetro, por lo que he simplificado el código anterior, y no se incluye el loadJSONDataFromURL función.

Pero, si usted está interesado, puede encontrar una copia de esta función de carga JSON en este blog: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm

Espero que esto ayude algunos otros desarrolladores XCode! (no se olvide de votar por esta pregunta y mi respuesta, si lo hace!)

+1

Este es realmente uno de los mejores trucos que he visto para iOS y bloques. ¡Ámalo hombre! – portforwardpodcast

1

escribí un completionBlock para una clase que devolverá los valores de los dados después de que han sido sacudidas:

  1. Definir typedef con returnType (.h anteriormente @interface declaración)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue); 
    
  2. definir un @property para el bloque (.h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling; 
    
  3. definir un método con finishBlock (.h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock; 
    
  4. método definido anterior Insertar en .m archivo e finishBlock a @property definido antes

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{ 
        self.completeDiceRolling = finishBlock; 
    } 
    
  5. Para desencadenar completionBlock pase predefinido variableType to it (No se olvide de comprobar si el completionBlock existe)

    if(self.completeDiceRolling){ 
        self.completeDiceRolling(self.dieValue); 
    } 
    
3

siempre tiendo a olvidar acerca de la sintaxis bloques. Esto siempre me viene a la mente cuando necesito declarar un bloque.Espero que ayude a alguien :)

http://fuckingblocksyntax.com

37

La explicación más fácil para esta pregunta es seguir estas plantillas:

1. Bloque como parámetro

Plantilla

- (void)aMethodWithBlock:(returnType (^)(parameters))blockName { 
     // your code 
} 

Ejemplo

-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{ 
     // your code 
} 

Otro uso de los casos:

2. Bloquear como una plantilla de propiedades

@property (nonatomic, copy) returnType (^blockName)(parameters); 

Ejemplo

@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error); 

3. Bloquear como un argumento método

Plantilla

[anObject aMethodWithBlock: ^returnType (parameters) { 
    // your code 
}]; 

Ejemplo

[self saveWithCompletionBlock:^(NSArray *array, NSError *error) { 
    // your code 
}]; 

4. Bloquear como una variable local

Plantilla

returnType (^blockName)(parameters) = ^returnType(parameters) { 
    // your code 
}; 

Ejemplo

void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){ 
    // your code 
}; 

5.Bloquear como un typedef

Plantilla

typedef returnType (^typeName)(parameters); 

typeName blockName = ^(parameters) { 
    // your code 
} 

Ejemplo

typedef void(^completionBlock)(NSArray *array, NSError *error); 

completionBlock didComplete = ^(NSArray *array, NSError *error){ 
    // your code 
}; 
+1

Una gran respuesta muchas gracias. –

+0

Great answer man.Far mejor que el aceptado.Gracias. – abhi1992

+0

Tan práctico y claro, que hace que esta respuesta sea la mejor, en mi opinión. – developermike

Cuestiones relacionadas