开发者

Can an Obj-C Block execute itself?

开发者 https://www.devze.com 2023-04-03 03:32 出处:网络
This is an extension of this queston: Is it possible to create a category of the "Block" object in Objective-C.

This is an extension of this queston: Is it possible to create a category of the "Block" object in Objective-C.

Basically while it seems possible to create a category on blocks, either through NSObject or NSBlock, I'm having trouble understanding how the block would be able to evaluate itself. The example given in the answer to the last question:

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

Implies that it is possible to somehow cast self to a block variable, but how would one execute the block itself? For example, say I did a category on NSBlock and in a method did:

NSBlock* selfAsBlock = (NSBlock*)self;

Is there any message I can send to开发者_如何学编程 selfAsBlock to have the block evaluate?


Implies that it is possible to somehow cast self to a block variable

Like this:

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

Note that (in most cases) you need to fix the block signature so that the compiler is able to set up the call site according to the target platform ABI. In the example above, the signature is return type int, single parameter of type int.

A full example is:

#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;
}


NSBlock has an invoke method that can be used to call the block.

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

Note that this is a private, undocumented method.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号