2011-09-06 13 views
7

यह इस खोज का विस्तार है: Is it possible to create a category of the "Block" object in Objective-Cक्या ओबीजे-सी ब्लॉक स्वयं निष्पादित कर सकता है?

मूल रूप से एनएसओब्जेक्ट या एनएसब्लॉक के माध्यम से ब्लॉक पर एक श्रेणी बनाने के लिए संभव लगता है, मुझे यह समझने में परेशानी हो रही है कि ब्लॉक खुद का मूल्यांकन कैसे कर पाएगा। उदाहरण पिछले सवाल का जवाब में दी गई:

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

मुझे नहीं लगता कि यह समस्या कैसे हल करती है। यह जवाब इस बात पर ध्यान केंद्रित करता है कि ब्लॉक को अपनी ब्लॉक परिभाषा के भीतर से कैसे कॉल करें। मैं ब्लॉक ऑब्जेक्ट से ब्लॉक का मूल्यांकन करने के बारे में बात कर रहा हूं। बस थोड़ा और विशिष्ट होने के लिए, मैं इसके साथ प्राप्त करने की उम्मीद कर रहा हूं, ब्लॉक आधारित नियंत्रण प्रवाह (यानी [ब्लॉक जबकि ट्राउड: ब्लॉक]) करने के लिए ब्लॉक (या तो एनएसओब्जेक्ट या एनएसब्लॉक पर) को जोड़ने के तरीकों को जोड़ने में सक्षम होना है। ऐसा करने के लिए मुझे विधि में स्वयं को पुनर्मूल्यांकन करने के लिए ब्लॉक की आवश्यकता है। – 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)); 
} 

ध्यान दें कि (ज्यादातर मामलों में) आप ऐसा ब्लॉक हस्ताक्षर को ठीक करने की जरूरत है कि संकलक लक्ष्य प्लेटफार्म एबीआई के अनुसार कॉल साइट सेट करने में सक्षम है। उपर्युक्त उदाहरण में, हस्ताक्षर वापसी प्रकार 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 जैसा कि आपने लिंक किया है, उसके जवाब में समझाया गया है, मुझे नहीं लगता कि एक श्रेणी का उपयोग करना संभव है क्योंकि संकलक को श्रेणी को पार करते समय मूल इंटरफ़ेस घोषणा की आवश्यकता होती है। –

4

NSBlock में invoke विधि है जिसका उपयोग ब्लॉक को कॉल करने के लिए किया जा सकता है।

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

ध्यान दें कि यह एक निजी, अनियंत्रित विधि है।

+1

यह वही तरीका है जिसे मैं ढूंढ रहा था। बेशक मुझे लगता है कि मैं जो कुछ भी कर रहा हूं वह खतरनाक है क्योंकि एनएसब्लॉक स्वयं निजी है और बदल सकता है। – donalbain

+0

यदि आप ब्लॉक को आमंत्रित करना चाहते हैं तो आप बस इस ब्लॉक(); [ब्लॉक आक्रमण] के बजाय; https://stackoverflow.com/a/9484268 – unmircea

संबंधित मुद्दे