2013-06-03 7 views
7

मैं ब्लॉक तर्कों को NSInvocation पर पास करने का प्रयास कर रहा हूं, लेकिन ऐप क्रैश हो जाता है। आमंत्रण नेटवर्क अनुरोध करता है और सफलता या विफलता ब्लॉक को कॉल करता है। मुझे लगता है कि समस्या यह है कि नेटवर्क अनुरोध समाप्त होने से पहले ब्लॉक को हटा दिया जाता है। मैं इसे Block_copy हैकररी के साथ काम करने में कामयाब रहा और यह इंस्ट्रूमेंट्स का उपयोग करके किसी भी रिसाव की रिपोर्ट नहीं करता है।ब्लॉक तर्कों के साथ एनएसआईएनवोकेशन

प्रश्न: - क्या यह संभव है कि स्थिर विश्लेषक या उपकरण इसकी रिपोर्ट नहीं कर रहे हैं, तो यह रिसाव है? - क्या ब्लॉक को "बनाए रखने" का कोई बेहतर तरीका है?

// Create the NSInvocation 
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector]; 
NSInvocation* invoc = [NSInvocation invocationWithMethodSignature:methodSignature]; 
[invoc setTarget:target]; 
[invoc setSelector:selector]; 

// Create success and error blocks. 
void (^successBlock)(id successResponse) = ^(id successResponse) { 
    // Some success code here ... 
}; 

void (^errorBlock)(NSError *error) = ^(NSError *error) { 
    // Some failure code here ... 
}; 

/* 
Without the two Block_copy lines, the block gets dealloced too soon 
and the app crashes with EXC_BAD_ACCESS 
I tried [successBlock copy] and [failureBlock copy] instead, 
but the app still crashes. 
It seems like Block_copy is the only way to move the block to the heap in this case. 
*/ 
Block_copy((__bridge void *)successBlock); 
Block_copy((__bridge void *)errorBlock); 
// Set the success and failure blocks. 
[invoc setArgument:&successBlock atIndex:2]; 
[invoc setArgument:&errorBlock atIndex:3]; 

[invoc retainArguments]; // does not retain blocks 

// Invoke the method. 
[invoc invoke]; 

अपडेट: मैंने कोड को नीचे अपडेट किया है। ब्लॉक NSMallocBlocks हैं, लेकिन ऐप अभी भी दुर्घटनाग्रस्त है।

// Create success and error blocks. 
int i = 0; 
void (^successBlock)(id successResponse) = ^(id successResponse) { 
    NSLog(@"i = %i", i); 
    // Some success code here ... 
}; 

void (^errorBlock)(NSError *error) = ^(NSError *error) { 
    NSLog(@"i = %i", i); 
    // Some failure code here ... 
}; 

/*** Both blocks are NSMallocBlocks here ***/ 
// Set the success and failure blocks. 
void (^successBlockCopy)(id successResponse) = [successBlock copy]; 
void (^errorBlockCopy)(NSError *error) = [errorBlock copy]; 

/*** Both blocks are still NSMallocBlocks here - I think copy is a NoOp ***/ 

// Set the success and failure blocks. 
[invoc setArgument:&successBlockCopy atIndex:2]; 
[invoc setArgument:&errorBlockCopy atIndex:3]; 

[invoc retainArguments]; // does not retain blocks 

// Invoke the method. 
[invoc invoke]; 

ब्लॉक श्रृंखला में नीचे पारित कर रहे हैं इस प्रकार है: → method1methodN

methodN अंततः HTTP के आधार पर सफलता या विफलता ब्लॉक कॉल

NSInvocationNSProxy (forwardInvocation:NSInvocation का प्रयोग करके) प्रतिक्रिया।

क्या मुझे हर चरण में ब्लॉक की प्रतिलिपि बनाने की आवश्यकता है? ऊपर दिया गया उदाहरण पहले NSInvocation के बारे में बात कर रहा था। क्या मुझे हर उचित चरण में [invocation retainArguments]; की भी आवश्यकता है? मैं एआरसी का उपयोग कर रहा हूँ।

उत्तर

8

Block_copy, और वास्तव में [block copy]वापसी प्रतियां। वे मूल रूप से एक ही स्थान पर एक प्रतिलिपि के साथ मूल रूप से स्विच नहीं करते हैं। तो कम से कम मुझे लगता है कि आप चाहते हैं:

successBlock = Block_copy((__bridge void *)successBlock); 
errorBlock = Block_copy((__bridge void *)errorBlock); 

(या, समतुल्य रूप, successBlock = [successBlock copy]; ...)

नहीं तो आप, प्रतियां बना रहे हैं उन लोगों के साथ कुछ नहीं कर रहे हैं और अभी भी मंगलाचरण के लिए रवाना मूल गुजर।

संपादित करें: हां, मैं एक परियोजना में निम्न कोड डाल:

@interface DummyClass: NSObject 
@end 

typedef void (^ successBlock)(id successResponse); 
typedef void (^ failureBlock)(NSError *error); 

@implementation DummyClass 

- (id)init 
{ 
    self = [super init]; 

    if(self) 
    { 
     SEL selector = @selector(someMethodWithSuccess:failure:); 
     id target = self; 

     // Create the NSInvocation 
     NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector]; 
     NSInvocation* invoc = [NSInvocation invocationWithMethodSignature:methodSignature]; 
     [invoc setTarget:target]; 
     [invoc setSelector:selector]; 

     // Create success and error blocks. 
     void (^successBlock)(id successResponse) = ^(id successResponse) { 
      // Some success code here ... 
      NSLog(@"Off, off, off with %@", successResponse); 
     }; 

     void (^errorBlock)(NSError *error) = ^(NSError *error) { 
      // Some failure code here ... 
      NSLog(@"Dance, dance, dance till %@", error); 
     }; 

     successBlock = [successBlock copy]; 
     errorBlock = [errorBlock copy]; 

     // Set the success and failure blocks. 
     [invoc setArgument:&successBlock atIndex:2]; 
     [invoc setArgument:&errorBlock atIndex:3]; 

     [invoc retainArguments]; // does not retain blocks 

     // Invoke the method. 
     double delayInSeconds = 2.0; 
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
     dispatch_after(popTime, dispatch_get_main_queue(), 
     ^{ 
      [invoc invoke]; 

     }); 
    } 

    return self; 
} 

- (void)someMethodWithSuccess:(successBlock)successBlock failure:(failureBlock)failureBlock 
{ 
    NSLog(@"Words:"); 
    successBlock(@[@"your", @"head"]); 
    failureBlock([NSError errorWithDomain:@"you're dead" code:0 userInfo:nil]); 
} 

@end 

और जोड़ा application:didFinishLaunchingWithOptions: के अंत में निम्नलिखित:

DummyClass *unusedInstance = [[DummyClass alloc] init]; 

परिणाम है कि दो सेकंड शुरू करने के बाद मेरे कार्यक्रम कंसोल पर निम्न प्रतीत होता है:

2013-06-02 20:11:56.057 TestProject[3330:c07] Words: 
2013-06-02 20:11:56.059 TestProject[3330:c07] Off, off, off with (
    your, 
    head 
) 
2013-06-02 20:11:56.060 TestProject[3330:c07] Dance, dance, dance till Error Domain=you're dead Code=0 "The operation couldn’t be completed. (you're dead error 0.)" 
+0

मैंने सफलता की कोशिश की हैब्लॉक = [सफलताब्लॉक पुलिस y]; और त्रुटिब्लॉक = [त्रुटि ब्लॉक कॉपी]; लेकिन मुझे इस त्रुटि के साथ एक ही दुर्घटना मिलती है: पते में कोई ऐसा अनुभाग नहीं होता है जो किसी ऑब्जेक्ट फ़ाइल में किसी सेक्शन को इंगित करता है। जैसा कि मैंने उल्लेख किया है, उल्लेख के अनुसार ब्लॉक_copy लाइनों को जोड़ना दुर्घटना को रोकता है, लेकिन मुझे यकीन नहीं है कि वे स्मृति को रिसाव करते हैं या नहीं। – pshah

+0

'ब्लॉक_copy' जिसका आप वर्तमान में उपयोग करते हैं उसका कोई दस्तावेज प्रभाव नहीं है। आप जो कुछ भी देख रहे हैं वह यह है कि समस्याग्रस्त 'इनवोक' के कारण अनिर्धारित परिणाम एक अलग अपरिभाषित प्रभाव रखते हैं। यह एक असली समाधान नहीं है। और यहां तक ​​कि लाश भी आपको डीबग करने में मदद नहीं करेंगे, क्योंकि वे ढेर वस्तुओं को कृत्रिम रूप से जीवित नहीं रख सकते हैं - एक बार ढेर बढ़ने के बाद यह उन्हें ओवरराइट कर देगा। – Tommy

+0

मैं इस धारणा के तहत था कि ब्लॉक_copy कॉलिंग ब्लॉक को ढेर के बजाय ढेर पर सहेजने के लिए मजबूर करता है। और, मैं अभी भी यह नहीं समझ सकता कि सफलता के बजाय [सफलताब्लॉक कॉपी] में क्यों गुजर रहा है आमंत्रण के लिए लॉग इन काम नहीं करेगा। – pshah

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