2011-09-06 60 views
7

這是這個queston的延伸: Is it possible to create a category of the "Block" object in Objective-CObj-C塊可以執行自己嗎?

基本上,雖然看起來有可能通過NSObject或NSBlock在塊上創建類別,但我無法理解塊如何能夠評估自己。在回答給最後一個問題的例子:

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

意味着它是可能以某種方式投自我塊變量,但如何將一個執行塊本身?例如,說我做了一個類別上NSBlock和方法都:

NSBlock* selfAsBlock = (NSBlock*)self; 

有沒有我可以向selfAsBlock有塊評估的任何消息?

+0

當然可以。你可以在這裏找到更多(已經在SO)http://stackoverflow.com/questions/4824613/is-there-a-self-pointer-for-blocks –

+0

我不明白如何解決這個問題。這個答案似乎集中在如何從自己的塊定義中調用塊。我正在討論從塊對象本身評估塊。只是爲了更具體一點,我希望能夠通過這個方法來添加方法(NSObject或NSBlock)來實現基於塊的控制流(即[Block whileTrueDo:block])。要做到這一點,我需要塊在方法中重新評估自己。 – donalbain

回答

7

意味着它是可能以某種方式施展自我塊可變

像這樣:

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

注意,(在大多數情況下),你需要修復的塊簽名,以便編譯器能夠根據目標平臺ABI建立呼叫站點。在上面的示例中,簽名是返回類型int,類型爲int的單個參數。

完整的例子就是:

#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

太好了。運行時顯式動態方法是否需要添加代碼?或者這也可以通過一個類別來完成? – donalbain

+1

@don正如你已經鏈接的問題的答案中所解釋的,我認爲不可能使用一個類別,因爲編譯器在解析類別時需要原始接口聲明。 – 2011-09-06 14:14:23

4

NSBlock有一個invoke方法可用於調用該塊。

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

請注意,這是一個私人的,未公開的方法。

+1

這就是我正在尋找的那種方法。當然,我想我在這裏所做的一切都是危險的,因爲NSBlock本身是私人的,可以改變。 – donalbain

+0

如果你想調用塊,你可以簡單地做這個塊();而不是[block invoke]; https://stackoverflow.com/a/9484268 – unmircea