2011-08-07 10 views
21
@implementation ThisObject 

-(void)start { 

     SomeOtherObject *someOtherObject = [SomeOtherObject alloc]; 

     [someOtherObject doSomethingAndCallThisFunctionWhenUrDone:myCallBackFunction :self]; 

} 

-(void)myCallBackFunction { 

     // :) 

} 

Básicamente, ¿cómo puedo hacer esto?En Objective C, ¿qué es el equivalente a pasar un puntero de función en C?

+0

Pero, ¿cuál es el lado del SomeOtherObject de esto? ¿Qué debe declararse en SomeOtherObject y qué necesita hacer? Tiene que tener un doSomethingAndCallThisFunctionWhenUrDone. Pero, ¿qué tiene que hacer para llamar a dicho método para el objeto ThisObject? Por cierto, un millón hasta ahora. – Joe

+0

Expandí mi respuesta para mostrar algunos detalles más de implementación. Para los punteros y bloques de función no necesita un objeto para llamarlos, pero puede pasar objetos como argumentos. – rbrown

Respuesta

3

¿Estás hablando de esto?

-(void)callSomePassedSelector:(SEL)callbackSelector { 
    [someObjectThatRespondesToThisSelector performSelector:callbackSelector]; 
} 

Asumo que desea almacenar y llamar más tarde, pero esto debe darle toda la información necesaria acerca de cómo pasar y lo llaman. Hay otros métodos para invocar el selector, ver más here

+0

¿Cómo pasaría en el selector? – TheJeff

0

estoy un poco confundido acerca de lo que está hablando, pero ¿es esto?

[self performSelector:@selector(myCallFunction)]; 
49

Hay cuatro maneras de hacer una devolución de llamada:

  1. puntero de función Usted puede hacer un puntero de función si realmente quiere, pero no es recomendable. Se hace de la misma manera que lo haría en C. El problema es que no puede usar un puntero a un método Objective-C. Se ve algo como esto:

    void callback(/* Some args */) { 
        // Some callback. 
    } 
    
    - (void)doSomethingAndCallThisFunctionWhenDone:(void(*)(/* Some args */))func { 
    
        // Do something. 
    
        if (func) 
         func(/* Some args */); 
    } 
    
    - (void)start { 
        [self doSomethingAndCallThisFunctionWhenDone:&callback]; 
    } 
    
  2. selectores Puede utilizar -performSelector :. Se ve así:

    - (void)doSomethingAndCallTarget:(id)target withSelector:(SEL)sel { 
    
        // Do something. 
    
        [target performSelector:sel]; 
    } 
    
    - (void)start { 
    
        SomeOtherObject * someOtherObject = [[SomeOtherObject alloc] init]; 
    
        [self doSomethingAndCallTarget:someOtherObject withSelector:@selector(MyCallback)]; 
    } 
    
  3. delegados uso de un delegado. Esto es similar a UITableViewDelegate/UITableViewDataSource. Vea el Apple docs here. Es posible hacerlo de esta manera:

    - (void)doSomethingDelegate:(id<MyCallbackObject>)delegate { 
    
        [delegate retain]; 
    
        // Do something. 
    
        [delegate performMyCallback]; // -performMyCallback must be declared in the MyCallbackObject protocol and implemented by SomeOtherObject. 
    
        [delegate release]; 
    } 
    
    - (void)start { 
    
        id<MyCallbackObject> someOtherObject = [[SomeOtherObject alloc] init]; 
    
        [self doSomethingDelegate:someOtherObject]; 
    
        [someOtherObject release]; 
    } 
    
  4. Bloques La forma preferida para las devoluciones de llamada es el uso de bloques. Solo están disponibles para iOS 4.0+ o Mac OS X 10.6+. Se ve algo como esto:

    - (void)doSomethingAndCallThisBlockWhenDone:(void(^)(/* Some args */))block { 
    
        [block copy]; 
    
        // Do something. 
    
        if (block) 
         block(/* Some args */); 
    
        [block release]; 
    } 
    
    - (void)start { 
        [self doSomethingAndCallThisBlockWhenDone:^void(/* Some args */){ // Return type and arguments may be omitted if you don't have any. 
         // Your callback 
        }]; 
    } 
    

Como se puede ver con el bloque, es más fácil de leer y su devolución de llamada está en línea con su código. Esto es especialmente bueno para que no tenga que cazarlo. Hay muchos más beneficios de bloques, pero posiblemente no podría cubrirlos a todos aquí.

Una última cosa, si usa un bloque, querrá usar un typedef para que no tenga que escribir tipos de bloques oscuros como void(^)(/* Some args */) todo el tiempo. El typedef podría tener este aspecto:

typdef void(^MyCallback)(/* Some args */); 

A continuación, se puede declarar su método como este:

- (void)doSomethingAndCallThisBlockWhenDone:(MyCallback)block; 

Actualización:

he mostrado más detalles de cómo implementar los diferentes técnicas (ver arriba).

+1

+1 bonita respuesta completa. Recuerde que si necesita que el bloque persista en un hilo diferente o más allá del giro actual del runloop, debe copiarse en el montón (o compila con ARC y lo hace The Right Thing ™) –

+0

Gracias Dave. Olvidé agregar ese detalle. Está ahí ahora. – rbrown

Cuestiones relacionadas