2011-08-07 18 views
21
Temelde

Amaç C'de bir işlev işaretçisini C'ye geçirmenin karşılığı nedir?

@implementation ThisObject 

-(void)start { 

     SomeOtherObject *someOtherObject = [SomeOtherObject alloc]; 

     [someOtherObject doSomethingAndCallThisFunctionWhenUrDone:myCallBackFunction :self]; 

} 

-(void)myCallBackFunction { 

     // :) 

} 
, bunu nasıl başarabiliriz?

+0

Ama bunların SomeOtherObject tarafı nedir? SomeOtherObject'te nelerin bildirilmesi gerekiyor ve ne yapması gerekiyor? Bir doSomethingAndCallThisFunctionWhenUrDone olması gerekir. Ancak, ThisObject nesnesinin adı geçen yöntemi çağırmak için gerçekte ne yapması gerekiyor? Şimdiye kadar bir milyonda bir milyon BTW. – Joe

+0

Bazı uygulama ayrıntılarını göstermek için cevabımı genişlettim. İşlev işaretçileri ve blokları için onları aramak için bir nesneye ihtiyacınız yoktur, ancak nesneleri argüman olarak iletebilirsiniz. – rbrown

cevap

3

bu bahsediyorsun?

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

Bunu saklamak ve daha sonra aramak istediğiniz varsayalım, ancak bu size geçmek ve onu aramak konusunda tüm gerekli bilgileri vermelidir. seçici çağırmak için başka yöntemler vardır, ne konuşuyordunuz hakkında biraz karışık here

+0

Seçiciden nasıl geçersiniz? – TheJeff

0

daha im bakın ama bu kadar mı?

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

Orada bir geri arama yapmak için dört yol vardır: Eğer gerçekten istiyorsan bir işlev işaretçisi yapabilirsiniz

  1. Fonksiyon Pointer, ancak tavsiye edilmez. Bu, C'de yaptığınız gibi yapılır. Sorun, bir Objective-C yöntemine bir işlev göstergesini kullanamazsınız. Bu şuna benzer:

    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. Seçiciler Sen -performSelector kullanabilirsiniz :. Bu şuna benzer:

    - (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. Delegeler kullanın bir temsilci. Bu UITableViewDelegate/UITableViewDataSource benzer. Apple docs here'a bakın. Böyle aynısını yaparsın: geri aramalar için

    - (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. Blokları Tercih yolu blokları kullanmaktır. Yalnızca iOS 4.0+ veya Mac OS X 10.6+ için kullanılabilirler. Bu şuna benzer: Eğer blokla görebileceğiniz gibi

    - (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 
        }]; 
    } 
    

, okumak daha kolay ve geri arama sizin koduyla satır içi olduğunu. Bu özellikle güzel çünkü onu avlamak zorunda değilsin. Blokların daha birçok faydası var, ama hepsini burada göremedim.

Son bir şey, bir blok kullanırsanız, typedef kullanmak isteyeceksiniz, böylece her zaman void(^)(/* Some args */) gibi belirsiz blok türleri yazmak zorunda kalmazsınız. typedef bu gibi görünebilir:

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

Ardından, bu gibi yöntemini ilan edebilir:

- (void)doSomethingAndCallThisBlockWhenDone:(MyCallback)block; 

Güncelleme:

farklı nasıl uygulanacağı daha ayrıntılı göstermiştir teknikler (yukarıya bakınız).

+1

+1 güzel kapsamlı yanıt. Farklı bir iş parçacığında veya runloop'un geçerli dönüşünün ötesinde kalması için bloğa ihtiyacınız varsa, yığının kopyalanması gerektiğini (ya da ARC ile derlediğinizin ve The Right Thing ™ 'ı hazırladığını) unutmayın. –

+0

Teşekkürler Dave. Bu detayı eklemeyi unuttum. Şimdi orada. – rbrown

İlgili konular