2011-10-20 10 views
7

मेरा ऐप आईओएस 5 में दुर्घटनाग्रस्त हो रहा है क्योंकि मेरे पास कुछ कोड है जो द्वितीयक थ्रेड से UIKit उदाहरणों को कॉल कर रहा है। तुम्हें पता है कि आप इस समस्या है जब आपको निम्न त्रुटि देखें:मैं माध्यमिक थ्रेड से UIKit उदाहरणों पर कॉल कैसे प्राप्त कर सकता हूं?

bool _WebTryThreadLock (bool), 0x811bf20: वेब धागे पर एकाधिक ताले अनुमति नहीं! कृपया एक बग फाइल करें। अब क्रैश हो रहा है ...

तो मेरा सवाल यह है कि मैं ऐसे तरीकों को ढूंढ सकता हूं जो यूआईकिट उदाहरणों को माध्यमिक धागे से बुला रहे हैं?

  1. ब्लॉक बाहर टिप्पणी की है कि स्थानों में शासन
  2. जोड़ा गया assert([NSThread isMainThread]) कि द्वितीय थ्रेड में प्रसंस्करण हो सकता है
  3. जोड़ा एक प्रतीकात्मक ब्रेकप्वाइंट का उल्लंघन किया जा सकता है:

    ये कुछ चीजें हैं मैं पहले से ही कर रहे हैं की कोशिश की है _WebTryThreadLock

इन चीजों ने मुझे समस्या क्षेत्रों को खोजने में मदद की है। हालांकि, मेरे अंतिम दुर्घटना में _WebTryThreadLock ब्रेकपॉइंट के किसी अन्य थ्रेड में कोई स्टैक ट्रेस नहीं है। तो, मैं उस कोड को कैसे ढूंढ सकता हूं जो बिना किसी स्टैक ट्रेस के समस्या का कारण बनता है?

आपके समय के लिए धन्यवाद!

+0

यह एक सिम्युलेटर बग हो सकता है।। क्या वास्तविक आईओएस डिवाइस पर चलते समय भी समस्या होती है? –

+0

हां, यह आईओएस 5 सिम्युलेटर और आईओएस डिवाइस आईओएस 5 चला रहा है। – johnnieb

+0

आह, ठीक है।उस त्रुटि संदेश की एक त्वरित Google खोज ने मुझे विश्वास दिलाया कि यह एक सिम्युलेटर बग था, लेकिन अगर यह कहीं और हो रहा है तो मुझे पूरी तरह से यकीन नहीं है। क्या आपको किसी भी मौके पर 2+ UIWebViews एक ही समय में स्क्रीन/लोडिंग पर प्रदर्शित होते हैं? –

उत्तर

3

आपका assert() शायद इस में सबसे महत्वपूर्ण उपकरण है। मैं अपने नियंत्रक वर्गों में हर विधि की शुरुआत में एक समान दावा करने के लिए जाना जाता हूं। अगर उसे यह नहीं मिलता है, तो मैं अपने व्यू क्लास में दावा जोड़ता हूं। अगर उसे यह नहीं मिलता है, तो मैं इसे किसी भी मॉडल वर्ग में जोड़ता हूं जो मुझे लगता है कि केवल मुख्य धागा है।

@ क्रेग की टिप्पणी, तथ्य यह है कि यह दावा है एक आंतरिक बग सही हो सकता है होना करने के लिए करने के लिए। लेकिन मुझे लगता है कि आप पहले अपने कोड की बारीकी से जांच करने के लिए सही रास्ते पर हैं।

1

यह समस्या तब आती है क्योंकि आप किसी भी तरह से माध्यमिक धागे से यूआई तक पहुंच बनाना चाहते हैं, यह किसी और चीज़ के वेबव्यू से हो सकता है। इसकी अनुमति नहीं है क्योंकि UIKit थ्रेड सुरक्षित नहीं है और केवल मेन थ्रेड से ही पहुंचा जा सकता है। सबसे पहले आप अपने थ्रेड कॉल को [self performSelectorOnMainThread:@selector(myMethod) withObject:nil waitUntilDone:NO]; (दस्तावेज़ों के लिए देखें) में बदलना चाहते हैं। मामले में जब आप कोई चारा आप GCD (ग्रांड सेंट्रल Dispathc) का उपयोग कर सकते हैं ...

1

इस कोड है मुख्य थ्रेड के बाहर UIKit उपयोग पर दावे का कारण बनता है (बस परियोजना और एआरसी के बिना इस फाइल को संकलित करने के लिए जोड़ने): https://gist.github.com/steipete/5664345

मैंने अभी कुछ कोडों में कई UIKit/मुख्य थ्रेड मुद्दों को चुनने के लिए इसका उपयोग किया है जिसे मैंने अभी उठाया है।

3

मैं PSPDFUIKitMainThreadGuard.m अनुकूलित एक इन चीजों के बारे में चिंता नहीं करने के लिए अनुमति देने के लिए। यहाँ: https://gist.github.com/k3zi/98ca835b15077d11dafc:

#import <objc/runtime.h> 
#import <objc/message.h> 

// Compile-time selector checks. 

#define PROPERTY(propName) NSStringFromSelector(@selector(propName)) 

// A better assert. NSAssert is too runtime dependant, and assert() doesn't log. 
// http://www.mikeash.com/pyblog/friday-qa-2013-05-03-proper-use-of-asserts.html 
// Accepts both: 
// - PSPDFAssert(x > 0); 
// - PSPDFAssert(y > 3, @"Bad value for y"); 
#define PSPDFAssert(expression, ...) \ 
do { if(!(expression)) { \ 
NSLog(@"%@", [NSString stringWithFormat: @"Assertion failure: %s in %s on line %s:%d. %@", #expression, __PRETTY_FUNCTION__, __FILE__, __LINE__, [NSString stringWithFormat:@"" __VA_ARGS__]]); \ 
abort(); }} while(0) 

/////////////////////////////////////////////////////////////////////////////////////////// 
#pragma mark - Helper for Swizzling 

BOOL PSPDFReplaceMethodWithBlock(Class c, SEL origSEL, SEL newSEL, id block) { 
    PSPDFAssert(c && origSEL && newSEL && block); 
    Method origMethod = class_getInstanceMethod(c, origSEL); 
    const char *encoding = method_getTypeEncoding(origMethod); 

    // Add the new method. 
    IMP impl = imp_implementationWithBlock(block); 
    if (!class_addMethod(c, newSEL, impl, encoding)) { 
     NSLog(@"Failed to add method: %@ on %@", NSStringFromSelector(newSEL), c); 
     return NO; 
    }else { 
     // Ensure the new selector has the same parameters as the existing selector. 
     Method newMethod = class_getInstanceMethod(c, newSEL); 
     PSPDFAssert(strcmp(method_getTypeEncoding(origMethod), method_getTypeEncoding(newMethod)) == 0, @"Encoding must be the same."); 

     // If original doesn't implement the method we want to swizzle, create it. 
     if (class_addMethod(c, origSEL, method_getImplementation(newMethod), encoding)) { 
      class_replaceMethod(c, newSEL, method_getImplementation(origMethod), encoding); 
     }else { 
      method_exchangeImplementations(origMethod, newMethod); 
     } 
    } 
    return YES; 
} 

// This installs a small guard that checks for the most common threading-errors in UIKit. 
// This won't really slow down performance but still only is compiled in DEBUG versions of PSPDFKit. 
// @note No private API is used here. 
__attribute__((constructor)) static void PSPDFUIKitMainThreadGuard(void) { 
    @autoreleasepool { 
     for (NSString *selStr in @[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) { 
      SEL selector = NSSelectorFromString(selStr); 
      SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", selStr]); 
      if ([selStr hasSuffix:@":"]) { 
       PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self, CGRect r) { 
        if(!NSThread.isMainThread){ 
         dispatch_async(dispatch_get_main_queue(), ^{ 
          ((void (*)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r); 
         }); 
        }else{ 
         ((void (*)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r); 
        } 
       }); 
      }else { 
       PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self) { 
        if(!NSThread.isMainThread){ 
         dispatch_async(dispatch_get_main_queue(), ^{ 
          ((void (*)(id, SEL))objc_msgSend)(_self, newSelector); 
         }); 
        }else 
         ((void (*)(id, SEL))objc_msgSend)(_self, newSelector); 
       }); 
      } 
     } 
    } 
} 

यह स्वचालित रूप से मुख्य थ्रेड में कॉल किक और इस तरह तुम भी कुछ भी लेकिन में कोड खटखटाने से करने की जरूरत नहीं होगी

+0

आपकी जिस्ट अब नहीं है –

+0

@AdamMendoza क्षमा करें, बस लिंक अपडेट किया गया – kezi

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