2011-09-06 33 views
7

Đây là phần mở rộng của nhiệm vụ này: Is it possible to create a category of the "Block" object in Objective-C.Khối Obj-C có thể tự thực thi không?

Về cơ bản trong khi có vẻ như có thể tạo danh mục trên các khối, thông qua NSObject hoặc NSBlock, tôi đang gặp khó khăn khi hiểu cách khối có thể tự đánh giá. Ví dụ được đưa ra trong câu trả lời cho câu hỏi cuối cùng:

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

ngụ ý rằng nó có thể bằng cách nào đó đúc tự cho một biến khối, nhưng làm thế nào người ta sẽ thực hiện khối chính nó? Ví dụ, nói rằng tôi đã làm một loại trên NSBlock và trong một phương pháp đã làm:

NSBlock* selfAsBlock = (NSBlock*)self; 

Có bất kỳ thông điệp nào tôi có thể gửi đến selfAsBlock để có khối đánh giá?

+0

Có bạn có thể. Bạn có thể tìm thấy thêm trong này (đã có trên SO) http://stackoverflow.com/questions/4824613/is-there-a-self-pointer-for-blocks –

+0

Tôi không thấy cách giải quyết vấn đề này. Câu trả lời đó dường như tập trung vào cách gọi một khối từ bên trong định nghĩa khối riêng của nó. Tôi đang nói về việc đánh giá một khối từ chính đối tượng khối. Chỉ cần một chút cụ thể hơn, những gì tôi hy vọng đạt được với điều này là có thể thêm các phương thức để chặn (hoặc trên NSObject hoặc NSBlock) để thực hiện luồng điều khiển dựa trên khối (nghĩa là [block whileTrueDo: block]). Để làm điều này, tôi cần khối để đánh giá lại chính nó trong phương pháp. – donalbain

Trả lời

7

ngụ ý rằng nó có thể bằng cách nào đó đúc tự đến một khối biến

Như thế này:

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

Lưu ý rằng (trong hầu hết các trường hợp), bạn cần phải sửa chữa chữ ký khối để rằng trình biên dịch có thể thiết lập trang web cuộc gọi theo nền tảng mục tiêu ABI. Trong ví dụ trên, chữ ký là kiểu trả về int, tham số đơn loại int.

Một ví dụ đầy đủ là:

#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

Tuyệt vời. Là phương pháp động thời gian chạy rõ ràng thêm mã cần thiết mặc dù? Hoặc điều này cũng có thể được thực hiện thông qua một thể loại? – donalbain

+1

@don Như đã giải thích trong câu trả lời cho câu hỏi bạn đã liên kết, tôi không nghĩ rằng có thể sử dụng danh mục vì trình biên dịch cần khai báo giao diện ban đầu khi phân tích cú pháp một danh mục. –

4

NSBlock có phương thức invoke có thể được sử dụng để gọi khối.

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

Lưu ý rằng đây là phương pháp riêng tư, không có giấy tờ.

+1

Đó là loại phương pháp tôi đang tìm kiếm. Tất nhiên tôi đoán tất cả mọi thứ tôi đang làm ở đây là nguy hiểm vì bản thân NSBlock là riêng tư và có thể thay đổi. – donalbain

+0

Nếu bạn muốn gọi khối, bạn chỉ cần thực hiện khối này(); thay vì [chặn cuộc gọi]; https://stackoverflow.com/a/9484268 – unmircea

Các vấn đề liên quan