2013-04-18 11 views
7

NSInvocation की -retainArguments विधि तब उपयोगी होती है जब आप तुरंत NSInvocation नहीं चलाते हैं, लेकिन बाद में ऐसा करते हैं; यह ऑब्जेक्ट तर्कों को बरकरार रखता है ताकि वे इस समय के दौरान वैध बने रहें।करता है - [एनएसआईएनवोकेशन retainArguments] ब्लॉक ब्लॉक?

जैसा कि हम सभी जानते हैं, अवरोध के बजाय ब्लॉक तर्कों की प्रतिलिपि बनाई जानी चाहिए। मेरा सवाल है, क्या -retainArguments ब्लॉक प्रकार के होने पर तर्क बनाए रखने के बजाय प्रतिलिपि बनाना है? दस्तावेज़ीकरण यह इंगित नहीं करता है कि यह करता है, लेकिन ऐसा करने के लिए यह एक आसान और समझदार चीज़ जैसा लगता है।

अद्यतन: व्यवहार मैं सिर्फ यह परीक्षण किया है, और iOS 6.1 में और इससे पहले कि, -retainArguments ब्लॉक प्रकार के मापदंडों कॉपी नहीं किया आईओएस 7 में बदल दिया है लगता है। आईओएस 7 और बाद में, -retainArguments ब्लॉक प्रकार के प्रति पैरामीटर करता है। -retainArguments का दस्तावेज यह कहने के लिए अद्यतन किया गया है कि यह ब्लॉक की प्रतिलिपि बनाता है, लेकिन यह तब नहीं कहता जब व्यवहार बदल गया (जो पुराने ओएस का समर्थन करने वाले लोगों के लिए वास्तव में खतरनाक है)।

+0

इस अद्यतन को रखने के लिए धन्यवाद! – matt

उत्तर

1

सं

छवि अगर जवाब है हां, जहां NSInvocation बहुत चालाक ब्लॉक कॉपी करने के लिए है, यह कुछ इस तरह करना चाहिए:

for (/*every arguments*/) { 
    if (/*arg is object. i.e. @encode(arg) is '@'*/) { 
     if ([arg isKindOfClss:[NSBlock class]]) { 
      arg = [arg copy]; // copy block 
     } else { 
      [arg retain]; 
     } 
    } 
} 

समस्या यह है कि arg जबकि को कॉपी संशोधित किया गया है है ब्लॉक, जो नहीं होना चाहिए क्योंकि इसका मतलब है retainArgumentsNSInvocation में तर्क बदल सकता है। इससे पहले से ही कई धारणाएं टूट जाएंगी। (यानी तर्क NSInvocation से प्राप्त एक ही होना चाहिए के रूप में तर्क बनाने के लिए इस्तेमाल किया NSInvocation)


अद्यतन

अभी किया जवाब अनुरूप परीक्षण नहीं है, लेकिन मेरे पिछले बात यह थी हालांकि गलत ...

@interface Test : NSObject 

@end 

@implementation Test 

- (void)testMethodWithBlock:(void (^)(void))block obj:(id)obj cstr:(const char *)cstr { 
    NSLog(@"%p %p %p %@", block, obj, cstr, [block class]); 
} 

@end 

@implementation testTests 

- (void)test1 { 
    __block int dummy; 
    Test *t = [[Test alloc] init]; 
    NSMethodSignature *ms = [t methodSignatureForSelector:@selector(testMethodWithBlock:obj:cstr:)]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:ms]; 
    void (^block)(void) =^{ 
     dummy++; // stop this become global block 
    }; 
    id obj = @"object"; 
    char *cstr = malloc(5); 
    strcpy(cstr, "cstr"); 


    NSLog(@"%@", [ms debugDescription]); 

    NSLog(@"%p %p %p %@", block, obj, cstr, [block class]); 

    [invocation setSelector:@selector(testMethodWithBlock:obj:cstr:)]; 
    [invocation setArgument:&block atIndex:2]; 
    [invocation setArgument:&obj atIndex:3]; 
    [invocation setArgument:&cstr atIndex:4]; 

    [invocation invokeWithTarget:t]; 

    [invocation retainArguments]; 

    [invocation invokeWithTarget:t]; 

    free(cstr); 
} 

@end 

उत्पादन, एआरसी अक्षम (और दुर्घटनाग्रस्त हो गया):

2013-04-18 19:49:27.616 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__ 
2013-04-18 19:49:27.617 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__ 
2013-04-18 19:49:27.618 test[94555:c07] 0xbfffe120 0x70d2254 0x736a810 __NSStackBlock__ 

एआरसी सक्षम:

2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__ 
2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__ 
2013-04-18 19:51:03.980 test[95323:c07] 0x7101e10 0x70d2268 0xe0c1310 __NSMallocBlock__ 

के रूप में आप देख सकते हैं, ग स्ट्रिंग retainArguments नहीं बल्कि ब्लॉक से कॉपी कर रहे हैं। लेकिन एआरसी सक्षम होने के साथ, समस्या दूर होनी चाहिए क्योंकि एआरसी ने इसे किसी बिंदु पर आपके लिए कॉपी किया है।

+0

ब्लॉक की प्रतिलिपि उस प्रकार की प्रणाली को बदलती नहीं है जो ब्लॉक सिस्टम के हस्ताक्षर की परवाह करता है। निश्चित रूप से, यह '__NSStackBlock__' से' __NSHeapBlock__' तक जा सकता है, लेकिन यह एक ब्लॉक की प्रतिलिपि बनाने का मुद्दा है: इसे अपने जीवनकाल को बढ़ाने के लिए ढेर में ले जाना। – CodaFi

+0

अच्छा बिंदु। हालांकि, '-retainArguments' भी सी तारों की प्रतिलिपि बनाता है। और सी तारों की प्रतिलिपि भी तर्क बदलती है। – user102008

+0

@ कोडाफ़ी मेरा बिंदु 'ब्लॉक है! = [ब्लॉक कॉपी]' इसलिए अगर –

4

यह निश्चित रूप से माना जाता है (हालांकि मैंने इसे स्वयं परीक्षण नहीं किया है)। documentation के अनुसार:

retainArguments

रिसीवर ऐसा पहले नहीं किया गया है, को बरकरार रखे हुए लक्ष्य और रिसीवर और प्रतियां सी-स्ट्रिंग तर्क और ब्लॉक के सभी के सभी वस्तु तर्क।

  • (शून्य) retainArguments

चर्चा

इससे पहले कि इस पद्धति शुरू हो जाती है, argumentsRetained रिटर्न नहीं; इसके बाद, यह हाँ देता है।

दक्षता के लिए, नव निर्मित NSInvocation वस्तुओं को बनाए रखने नहीं है या उनके तर्कों की प्रतिलिपि, और न ही वे अपने लक्ष्य को बनाए रखने करते हैं, नकल सी तार, या किसी भी संबद्ध ब्लॉक कॉपी। यदि आप इसे कैश करना चाहते हैं तो एनएसआईएनवोकेशन ऑब्जेक्ट को अपने तर्कों को बनाए रखने के लिए निर्देश देना चाहिए, क्योंकि अन्यथा आमंत्रण से पहले तर्क जारी किया जा सकता है। एनएसटीमर ऑब्जेक्ट्स हमेशा अपने आविष्कार को पर निर्देश देते हैं, उदाहरण के लिए, क्योंकि आमतौर पर टाइमर आग से पहले देरी होती है।

+0

दिलचस्प। दस्तावेज़ीकरण बदल गया है: https://web.archive.org/web/20120826185131/http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html # // apple_ref/occ/instm/nSInvocation/retainArguments लेकिन यह व्यवहार नहीं करता है कि व्यवहार कब और कब बदलता है। जब मैंने एक साल पहले आईओएस 6 में कोशिश की तो ब्लॉक को 'retainArguments' द्वारा निश्चित रूप से कॉपी नहीं किया गया था। – user102008

+1

मैंने अभी इसका परीक्षण किया है, और यह आईओएस 7 में कॉपी किया गया है लेकिन आईओएस 6.1 में नहीं, इसलिए यह बदल गया। – user102008

+0

उन्हें परिवर्तन को आईओएस 7 अपडेट के रूप में दस्तावेज करना चाहिए था क्योंकि ऐसा लगता है कि ऐसा हमेशा ऐसा होता है ... मूर्ख ऐप्पल, चाल बच्चों के लिए हैं! –

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