2009-06-18 11 views
109

Come eseguire le funzioni di richiamata in Objective-C?Come eseguire le richiamate in Objective-C

Vorrei solo vedere alcuni esempi completati e dovrei capirlo.

+3

Questa domanda è sorprendente e le risposte sono davvero utili .. –

+0

non immagina che sia così difficile da capire ......... –

risposta

89

Normalmente, le richiamate nell'obiettivo C vengono eseguite con i delegati. Ecco un esempio di implementazione personalizzata dei delegati;

/// Header File 
@interface MyClass : NSObject { 
    id delegate; 
} 
- (void)setDelegate:(id)delegate; 
- (void)doSomething; 
@end 

@interface NSObject(MyDelegateMethods) 
- (void)myClassWillDoSomething:(MyClass *)myClass; 
- (void)myClassDidDoSomething:(MyClass *)myClass; 
@end 


/// Message (.m) File 
@implementation MyClass 
- (void)setDelegate:(id)aDelegate { 
    delegate = aDelegate; /// Not retained 
} 

- (void)doSomething { 
    [delegate myClassWillDoSomething:self]; 
    /* DO SOMETHING */ 
    [delegate myClassDidDoSomething:self]; 
} 
@end 

Che illustra l'approccio generale. Si crea una categoria su NSObject che dichiara i nomi dei metodi di callback. NSObject in realtà non implementa questi metodi. Questo tipo di categoria è chiamato protocollo informale, stai solo dicendo che molti oggetti potrebbero implementare questi metodi. Sono un modo per inoltrare la dichiarazione del tipo del selettore.

Successivamente si ha qualche oggetto come delegato di "MyClass" e MyClass chiama i metodi delegati sul delegato come appropriato. Se i callback dei delegati sono opzionali, generalmente li proteggi nel sito di spedizione con qualcosa come "if ([delegate respondsToSelector: @selector (myClassWillDoSomething :)) {". Nel mio esempio, al delegato è richiesto di implementare entrambi i metodi.

Invece di un protocollo informale, è possibile utilizzare anche un protocollo formale definito con @protocol. Se lo fai, cambieresti il ​​tipo del setter delegato e la variabile di istanza fosse "id <MyClassDelegate>" invece di "id".

Inoltre, si noterà che il delegato non viene mantenuto. Questo in genere viene eseguito perché l'oggetto che "possiede" istanze di "MyClass" è in genere anche il delegato. Se MyClass ha mantenuto il suo delegato, allora ci sarebbe un ciclo di conservazione. È una buona idea nel metodo dealloc di una classe che abbia un'istanza MyClass ed è il suo delegato a cancellare quel riferimento delegato poiché è un debole back pointer. Altrimenti, se qualcosa mantiene in vita l'istanza di MyClass, avrai un puntatore pendente.

+0

+1 Buona risposta completa. La ciliegina sulla torta sarebbe un link a una documentazione Apple più approfondita sui delegati. :-) –

+0

Jon, grazie mille per il tuo aiuto. Apprezzo molto il vostro aiuto. Mi dispiace per questo, ma non sono molto chiaro sulla risposta. Il messaggio .m è una classe che si imposta come delegato durante la chiamata della funzione doSomething. Qualcosa è la funzione di callback che l'utente chiama? poiché ho l'impressione che l'utente chiami DoSomething e le funzioni di richiamata sono myClassWillDoSomethingg & myClassDidDoSomething. Inoltre, puoi mostrarmi come creare una classe superiore che richiami la funzione di richiamata. Sono un programmatore C quindi non ho ancora familiarità con l'ambiente Obj-C. – ReachConnection

+0

"Messaggio .m" voleva dire, nel tuo file .m. Avresti una classe separata, chiamiamola "Pippo". Foo avrebbe una variabile "MyClass * myClass", e ad un certo punto Foo direbbe "[myClass setDelegate: self]". In seguito, se qualcuno che include foo ha invocato il metodo doSomething su quell'istanza di MyClass, foo avrebbe i suoi metodi myClassWillDoSomething e myClassDidDoSomething richiamati. In realtà pubblicherò anche un secondo esempio diverso che non utilizza i delegati. –

46

Ecco un esempio che mantiene i concetti dei delegati e fa semplicemente una chiamata non valida.

@interface Foo : NSObject { 
} 
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector; 
@end 

@interface Bar : NSObject { 
} 
@end 

@implementation Foo 
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector { 
    /* do lots of stuff */ 
    [object performSelector:selector withObject:self]; 
} 
@end 

@implementation Bar 
- (void)aMethod { 
    Foo *foo = [[[Foo alloc] init] autorelease]; 
    [foo doSomethingAndNotifyObject:self withSelector:@selector(fooIsDone:)]; 
} 

- (void)fooIsDone:(id)sender { 
    NSLog(@"Foo Is Done!"); 
} 
@end 

genere il metodo - [Foo doSomethingAndNotifyObject: withSelector:] sarebbe asincrona che rendono la richiamata più utile è qui.

+1

Grazie mille John. Capisco la tua prima implementazione di callback dopo i tuoi commenti. Inoltre, la tua seconda implementazione callback è più semplice. Entrambi sono molto buoni. – ReachConnection

+1

Grazie per aver postato questo Jon, è stato molto utile. Ho dovuto cambiare [oggetto performSelectorwithObject: self]; a [oggetto performSelector: selector withObject: self]; per farlo funzionare correttamente. – Banjer

+0

Abbastanza sicuro, è una classica risposta StackOverflow :) Ehi, qualcuno dovrebbe espandersi un po 'su "In genere il metodo sarebbe asincrono ..." forse un esempio di quello ?? Eccezionale. – Fattie

130

Per completezza, dal momento che StackOverflow RSS resuscitato appena a caso la questione per me, l'altra opzione (più recente) è quello di utilizzare i blocchi:

@interface MyClass: NSObject 
{ 
    void (^_completionHandler)(int someParameter); 
} 

- (void) doSomethingWithCompletionHandler:(void(^)(int))handler; 
@end 


@implementation MyClass 

- (void) doSomethingWithCompletionHandler:(void(^)(int))handler 
{ 
    // NOTE: copying is very important if you'll call the callback asynchronously, 
    // even with garbage collection! 
    _completionHandler = [handler copy]; 

    // Do stuff, possibly asynchronously... 
    int result = 5 + 3; 

    // Call completion handler. 
    _completionHandler(result); 

    // Clean up. 
    [_completionHandler release]; 
    _completionHandler = nil; 
} 

@end 

... 

MyClass *foo = [[MyClass alloc] init]; 
int x = 2; 
[foo doSomethingWithCompletionHandler:^(int result){ 
    // Prints 10 
    NSLog(@"%i", x + result); 
}]; 
+0

ama questa soluzione, simile alla funzione anonima per i callback, semplice, meno codice da scrivere. – David

+2

@Ahruman: Che cosa significa il carattere "^" in "void (^ _completionHandler) (int someParameter);" significare? Potresti spiegare cosa fa quella linea? –

+0

Blocks semplifica inoltre il wrapping di callback in stile C (i puntatori di funzione che contengono parametri 'void *') in blocchi. Ho scritto un esempio su come farlo qui: [Avvolgere callback in stile C con blocchi] (http://cutecoder.org/programming/wrapping-style-callbacks-blocks/). – adib

5

Per mantenere questa domanda up-to-date, di iOS 5.0 introduzione di ARC significa che questo può essere realizzato utilizzando Blocks ancora più conciso:

@interface Robot: NSObject 
+ (void)sayHi:(void(^)(NSString *))callback; 
@end 

@implementation Robot 
+ (void)sayHi:(void(^)(NSString *))callback { 
    // Return a message to the callback 
    callback(@"Hello to you too!"); 
} 
@end 

[Robot sayHi:^(NSString *reply){ 
    NSLog(@"%@", reply); 
}]; 

C'è sempre F****ng Block Syntax se mai dimenticare la sintassi del blocco di Objective-C.

+0

In @interface dovrebbe essere '+ (void) sayHi: (void (^) (NSString * reply)) callback;' not '+ (void) sayHi: (void (^) (NSString *)) callback' –

+0

Not in accordo con la già menzionata [F **** ng Block Syntax] (http://goshdarnblocksyntax.com/): '- (void) someMethodThatTakesABlock: (returnType (^ nullability) (parameterTypes)) blockName;' (Nota 'parameterTypes' not 'parameters') –

3

CallBack: Ci sono 4 tipi di callback in Objective C

  1. Tipo Selettore: Si può vedere NSTimer, UIPangesture sono gli esempi di Selettore di callback. Utilizzato per l'esecuzione di codice molto limitata.

  2. Tipo di delegato: comune e più utilizzato nel framework Apple. UITableViewDelegate, NSNURLConnectionDelegate. Essi sono di solito utilizzati per mostrare molte immagini Download da server in modo asincrono ecc

  3. NSNotifications: NotificationCenter è una delle caratteristiche di Objective C che ha usato per comunicare molte receiptants al momento in cui si verificano eventi.
  4. Blocchi: i blocchi sono più comunemente utilizzati nella programmazione in Objective C. È una funzione eccezionale e viene utilizzata per eseguire blocchi di codice. Puoi anche riferirti all'esercitazione per capire: Blocks tutorial

Per favore lasciatemi se ci sono altre risposte. Io lo apprezzerei.

Problemi correlati