5

यह की तर्ज पर आईओएस विकास सलाह को देखने के लिए असामान्य नहीं है: उद्देश्य-सी में नामकरण ब्लॉक?

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    // work in background 
    NSLog(@"%s work", __PRETTY_FUNCTION__); 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // update UI on main queue 
     NSLog(@"%s updateUI", __PRETTY_FUNCTION__); 
    }); 
}); 

यह महान है, लेकिन यह डिबग करने के लिए कठिन हो सकता है जब कुछ गलत हो जाता। उत्पादन को देखते हुए:

AppName[1051:4013] __47-[Classname methodName]_block_invoke_0 work 
AppName[1051:907] __block_global_0 updateUI 

पहले लॉग लाइन वर्ग और विधि के नाम है तो हम बाहरी ब्लॉक में एक मुद्दा (उम्मीद है कि हम उस विधि में कई ब्लॉक परिभाषित नहीं किया है) पर नज़र रखने की कुछ उम्मीद है, लेकिन दूसरी लॉग-लाइन (आंतरिक ब्लॉक से)? शुभकामनाएं, खासकर अगर आपने इस ऐप को अपने ऐप में बहुत कुछ इस्तेमाल किया है।

वहाँ एक रास्ता ब्लॉक के नाम जो हमें सांत्वना उत्पादन और दुर्घटना लॉग में उनके स्रोत पहचान कर सकते हैं देने के लिए है?

+1

वैकल्पिक रूप से, आप ब्लॉक में एक ब्रेकपाइंट सेट कर सकते हैं और जब यह तक भर चुकी है डीबगर एक स्टैक ट्रेस आप कम से वमन जाएगा (जो ज्यादातर मामलों में IME अधिक 'NSLog' से उपयोगी है)। –

+0

मैं ब्रेकपॉइंट्स का भी उपयोग करता हूं, और कभी भी ब्लॉक द्वारा वंचित महसूस नहीं किया है। – danh

+3

मुझे नहीं लगता कि ब्लॉक के नामकरण में बनाया गया है, लेकिन आप निश्चित रूप से कतारों का नाम दे सकते हैं, जो आपको रास्ते का हिस्सा बनता है। यह डीबगर में दिखाई देता है और आप एनएसएलओजी कथन में शामिल कर सकते हैं। वैकल्पिक रूप से, आप भी '__FILE__' और' __LINE__' का उपयोग कर सकते हैं। शायद अपने स्वयं के मैक्रो को परिभाषित करें जो उपरोक्त का संयोजन है। – Rob

उत्तर

0

एक चीज जो आप कर सकते हैं वह ब्लॉक के बजाय फ़ंक्शन का उपयोग करना है, और dispatch_async के बजाय dispatch_async_f है। ट्रेडऑफ महत्वपूर्ण हैं, क्योंकि आप ब्लॉक की इनलाइन कोड प्रकृति खो देते हैं, और एक संदर्भ सूचक के माध्यम से इसे मार्शल किए बिना राज्य को पकड़ने की क्षमता खो देते हैं।

आप, साथ ही बाहरी ब्लॉक के बाहर भीतरी ब्लॉक घोषित करने और एक स्थानीय चर में यह भी छिपा सकते हो सकता है। थोड़ा कम संक्षेप में, लेकिन यह इसे बाहरी ब्लॉक की तरह संलग्न विधि के नाम से टैग करेगा।

4

ब्लाकों, एक बार की नकल की, NSBlock, जिसका अर्थ है कि हम तो यह अच्छा चीजों के सभी प्रकार जोड़ने के लिए क्रम का उपयोग कर सकते के उदाहरण बन जाते हैं।

@protocol QuietTheCompiler<NSObject> 
- (NSString*) prettyBlockDescription; 
@end 

static id beautifyBlockDescription(id block, NSString *name) 
{ 
    static void *kAssocObjectPrettyBlockDescription = "A"; 
    Class blockClass = [block class]; 

    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 

     SEL descrSel  = @selector(description); 
     SEL prettySel = @selector(prettyBlockDescription); 
     Method descrMethod = class_getInstanceMethod(blockClass, descrSel); 
     IMP originalImpl = class_getMethodImplementation(blockClass, descrSel); 

     IMP prettyImpl = imp_implementationWithBlock(^(id self_) { 
      id value = objc_getAssociatedObject(self_, kAssocObjectPrettyBlockDescription); 
      return (value != nil)? value : originalImpl(self_, descrSel); 
     }); 

     if (class_addMethod(blockClass, prettySel, prettyImpl, method_getTypeEncoding(descrMethod))) { 
      IMP newImpl = imp_implementationWithBlock(^(id self_) { 
       return [self_ prettyBlockDescription]; 
      }); 
      class_replaceMethod(blockClass, descrSel, newImpl, method_getTypeEncoding(descrMethod)); 
     } 
    }); 

    NSString *description = [NSString stringWithFormat:@"<%@: %p name=%@>",NSStringFromClass(blockClass),block,name]; 
    objc_setAssociatedObject(block, kAssocObjectPrettyBlockDescription, description, OBJC_ASSOCIATION_RETAIN); 

    return block; 
} 


int main (int argc, const char * argv[]) 
{ 
    @autoreleasepool { 

     int (^block1)(int,NSString*) = ^(int i, NSString *fmt) { 
      return i; 
     }; 

     id blockObject1 = beautifyBlockDescription([block1 copy], @"Hello"); 

     int (^block2)(int,NSString*) = ^(int i, NSString *fmt) { 
      return i+1; 
     }; 

     id blockObject2 = [block2 copy]; 

     NSLog(@"Block 1: %@", blockObject1); 
     NSLog(@"Block 1: %@", blockObject2); 
    } 
    return 0; 
} 

यहाँ इस कार्यक्रम का उत्पादन किया जाता है::

// Sample Output 
2013-03-31 12:34:48.984 Dummy[1231:303] Block 1: <__NSGlobalBlock__: 0x1000059d0 name=Hello> 
2013-03-31 12:34:48.987 Dummy[1231:303] Block 1: <__NSGlobalBlock__: 0x100005a10> 

मेरा सुझाव है कि आप एक मैक्रो में beautifyBlockDescription समारोह लपेट ताकि रिहाई कोड के लिए यह सिर्फ ब्लॉक रिटर्न यहाँ एक उदाहरण है।

+0

शायद बहुत जटिल लेकिन बहुत रोचक! – Sulthan

+0

यह थोड़ा जटिल है लेकिन रनटाइम के साथ खेलना वास्तव में कभी आसान नहीं होता है। यह फ़ंक्शन का प्रकार भी है जो एक छोटी लाइब्रेरी में अच्छी तरह फिट बैठता है जो फिर से उपयोग किया जाता है ... – aLevelOfIndirection

0

आप https://github.com/conradev/BlockTypeDescription का उपयोग कर विकास के दौरान लॉग के पठनीयता में सुधार करने की कोशिश कर सकता है। हालांकि, यह लाइब्रेरी निजी एनएसब्लॉक क्लास पर एक विधि को प्रतिस्थापित करती है, आपको कभी भी ऐपस्टोर बाइनरी में इसका उपयोग करने की कोशिश नहीं करनी चाहिए या इसे खारिज कर दिया जाएगा। जिसका अर्थ है कि आप ऐप्पल से प्राप्त क्रैशलॉग को बेहतर नहीं कर सकते हैं।