Может ли блок Obj-C выполняться сам? - PullRequest
7 голосов
/ 06 сентября 2011

Это расширение этого квеста: Возможно ли создать категорию объекта "Блок" в Objective-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 для оценки блока?

Ответы [ 2 ]

7 голосов
/ 06 сентября 2011

Подразумевает, что можно как-то привести себя к переменной блока

Как это:

- (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;
}
4 голосов
/ 06 сентября 2011

NSBlock имеет метод invoke, который можно использовать для вызова блока.

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

Обратите внимание, что это частный недокументированный метод.

...