2011-09-06 13 views
7

Jest to rozszerzenie tego Queston: Is it possible to create a category of the "Block" object in Objective-C.Czy blok Obj-C może wykonać się sam?

Zasadniczo gdy wydaje się możliwe, aby utworzyć kategorię na blokach, albo poprzez NSObject lub NSBlock, mam problemy ze zrozumieniem jak blok będzie w stanie ocenić sam. Przykład podany w odpowiedzi na ostatnie pytanie:

- (void) doFoo { 
    //do something awesome with self, a block 
    //however, you can't do "self()". 
    //You'll have to cast it to a block-type variable and use that 
} 

oznacza, że ​​możliwe jest, aby w jakiś sposób rzucić ja do zmiennej bloku, ale w jaki sposób można by wykonać samego bloku? Na przykład, powiedzmy zrobiłem kategorię na NSBlock aw metodzie udało:

NSBlock* selfAsBlock = (NSBlock*)self; 

Czy istnieje mogę wysłać wiadomość do selfAsBlock mieć blok oceniać?

+0

Tak można. Można znaleźć więcej na ten (już na SO) http://stackoverflow.com/questions/4824613/is-there-a-self-pointer-for-blocks –

+0

nie widzę, w jaki sposób rozwiązuje ten problem. Ta odpowiedź wydaje się koncentrować na sposobie wywoływania bloku z własnej definicji bloku. Mówię o ocenie bloku z samego obiektu bloku. Wystarczy być nieco bardziej szczegółowe, co mam nadzieję osiągnąć to, aby móc dodać metody do bloków (zarówno na NSObject lub NSBlock) zrobić przepływ sterowania oparty bloku (czyli [blok whileTrueDo: blok]). Aby to zrobić, potrzebuję bloku, aby dokonać ponownej oceny w metodzie. – donalbain

Odpowiedz

7

oznacza, że ​​możliwe jest, aby w jakiś sposób rzucić siebie do bloku zmiennej

tak:

- (void)doFoo { 
    // Assume the block receives an int, returns an int, 
    // and cast self to the corresponding block type 
    int (^selfBlock)(int) = (int (^)(int))self; 

    // Call itself and print the return value 
    printf("in doFoo: %d\n", selfBlock(42)); 
} 

Zauważ, że (w większości przypadków) trzeba naprawić podpis bloku tak że kompilator jest w stanie skonfigurować witrynę połączenia zgodnie z docelową platformą ABI. W powyższym przykładzie, podpis jest powrót typu int, jeden parametr typu int.

Pełną przykładem jest:

#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

@interface Foo : NSObject 
- (void)doFoo; 
@end 

@implementation Foo 
- (void)doFoo { 
    // Assume the block receives an int, returns an int, 
    // and cast self to the corresponding block type 
    int (^selfBlock)(int) = (int (^)(int))self; 

    // Call itself and print the return value 
    printf("in doFoo: %d\n", selfBlock(42)); 
} 
@end 

int main(void) { 
    [NSAutoreleasePool new]; 

    // From Dave's answer 
    Method m = class_getInstanceMethod([Foo class], @selector(doFoo)); 
    IMP doFoo = method_getImplementation(m); 
    const char *type = method_getTypeEncoding(m); 
    Class nsblock = NSClassFromString(@"NSBlock"); 
    class_addMethod(nsblock, @selector(doFoo), doFoo, type); 

    // A block that receives an int, returns an int 
    int (^doubler)(int) = ^int(int someNumber){ return someNumber + someNumber; }; 

    // Call the category method which in turn calls itself (the block) 
    [doubler doFoo]; 

    return 0; 
} 
+0

Świetnie. Czy jednak niezbędna jest metoda dynamicznego dodawania dynamicznego środowiska wykonawczego? Czy można to zrobić również poprzez kategorię? – donalbain

+1

@don Jak wyjaśniono w odpowiedzi na pytanie już powiązane, nie sądzę, że to możliwe, aby użyć kategorię ponieważ kompilator musi oryginał deklaracji interfejsu podczas analizowania kategorię. –

4

NSBlock ma invoke sposobu, który może być użyty do wywołania blokady.

NSBlock* b = ^() { /* do stuff */ }; 
[b invoke]; 

Należy pamiętać, że jest to metoda prywatna, nieudokumentowana.

+1

Takiej właśnie metody szukałem. Oczywiście domyślam się, że wszystko, co tu robię, jest niebezpieczne, ponieważ sama NSBlock jest prywatna i może się zmienić. – donalbain

+0

Jeśli chcesz wywołać blok, możesz po prostu zrobić ten blok(); zamiast [block invoke]; https://stackoverflow.com/a/9484268 – unmircea