iOS बैकग्राउंड थ्रेड शुरू करते हैं


117

मेरे पास अपने iOS डिवाइस में एक छोटा सा sqlitedb है। जब कोई उपयोगकर्ता एक बटन दबाता है, तो मैं डेटा को sqlite से प्राप्त करता हूं और इसे उपयोगकर्ता को दिखाता हूं।

यह लाने वाला हिस्सा मैं इसे एक बैकग्राउंड थ्रेड (UI मुख्य थ्रेड को ब्लॉक नहीं करने के लिए) करना चाहता हूं। मैं ऐसा करता हूं -

[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];

लाने और थोड़ी सी प्रोसेसिंग के बाद, मुझे UI अपडेट करना होगा। लेकिन चूंकि (एक अच्छे अभ्यास के रूप में) हमें बैकग्राउंड थ्रेड्स से यूआई अपडेशन नहीं करना चाहिए। मैं selectorमेनहार्ट पर कॉल करता हूँ जैसे -

[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];

लेकिन मेरा ऐप पहले चरण में क्रैश हो गया। यानी बैकग्राउंड थ्रेड शुरू करना। क्या यह iOS में बैकग्राउंड थ्रेड शुरू करने का तरीका नहीं है?

अद्यतन 1:[self performSelectorInBackground.... मैं इस स्टैकट्रेस प्राप्त करने के बाद , कोई जानकारी नहीं है कि क्या कभी -

यहां छवि विवरण दर्ज करें

अद्यतन 2: मैंने भी कोशिश की थी, जैसे कि एक पृष्ठभूमि धागा शुरू करना - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];लेकिन फिर भी मुझे वही स्टैकट्रेस मिलता है।

बस इतना है कि मैं स्पष्ट करता हूं, जब मैं इस ऑपरेशन को मुख्य धागे पर करता हूं तो सब कुछ सुचारू रूप से चलता है ...

अद्यतन 3 यह वह विधि है जिसे मैं पृष्ठभूमि से चलाने की कोशिश कर रहा हूं

- (void)getResultSetFromDB:(NSMutableArray *)toProceessDocids
{
    SpotMain *mirror = [[SpotMain alloc] init];
    NSMutableArray *filteredDocids = toProceessDocids;

    if(![gMediaBucket isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaBucketWithDocID:filteredDocids mBucket:gMediaBucket numRes:-1];
    if(![gMediaType isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaType:filteredDocids mediaType:gMediaType numRes:-1];
    if(![gPlatform isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForPlatformID:filteredDocids platformId:@"1" numRes:-1];

    self.resultSet = [mirror FetchObjectFromDocid:filteredDocids];
    [filteredDocids release];
    [mirror release];

    [self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
    return;
}

आपको क्या त्रुटि / क्रैश लॉग मिलता है?
jtbandes

कृपया मेरे अपडेट देखें ...
Srikar Appalaraju

क्या आप कृपया उस पद्धति को दिखा सकते हैं जिसे आप पृष्ठभूमि में बुला रहे हैं? और सुनिश्चित करें कि वस्तु docidsको बरकरार रखा गया है।
रोज

हाँ, docidsकर रहे हैं retain। मैंने इसे .h@property (nonatomic, retain) NSMutableArray *docids;
kar- श्रीकर अप्पलाराजु

के साथ उपसर्ग विधि न करें get; बस यही होना चाहिएresultSetFromDB:
bbum

जवाबों:


270

यदि आप performSelectorInBackground:withObject:एक नया धागा स्पॉन करने के लिए उपयोग करते हैं, तो नया चयन ऑटोरिएलेज़ पूल, रन लूप और अन्य कॉन्फ़िगरेशन विवरण सेट करने के लिए जिम्मेदार चयनकर्ता जिम्मेदार है - Apple के थ्रेडिंग प्रोग्रामिंग गाइड में "NSObject to Spawn a Thread" का उपयोग करना देखें

आप शायद ग्रैंड सेंट्रल डिस्पैच का उपयोग करना बेहतर होगा , हालांकि:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self getResultSetFromDB:docids];
});

जीसीडी एक नई तकनीक है, और मेमोरी ओवरहेड और कोड की लाइनों के मामले में अधिक कुशल है।


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


ठंडा! यह नहीं पता था। क्या यह [NSThread detachNewThreadSelector:@selector....भी लागू होता है ?
श्रीकर अप्पाराजु

हाँ। Apple डॉक्स के अनुसार, performSelectorInBackground:withObject:"आप वर्तमान ऑब्जेक्ट, चयनकर्ता और पैरामीटर ऑब्जेक्ट के साथ पैरामीटर के रूप में detachNewThreadSelector:toTarget:withObject:विधि को कॉल करते हैं, तो कॉलिंग समान है NSThread।"
स्कॉट फोर्ब्स

क्या इस मामले में (unsigned long)NULLऔर अंतर 0है?
Sti

4
@Sti से सेब देव डॉक्स : नोट: dispatch_get_global_queue कार्य करने के लिए दूसरा तर्क भावी विस्तार के लिए आरक्षित है। अभी के लिए, आपको इस तर्क के लिए हमेशा 0 पास करना चाहिए।
जावद अल शेख

क्या मुझे तब ऑपरेशन के परिणामों के साथ UI को अपडेट करने के लिए performSelectorOnMainThread का उपयोग करना चाहिए या जीसीडी के साथ यूआई को अपडेट करने का अधिक सुसंगत तरीका है?
इल्या डेनिसोव

9

वास्तव में यह वास्तव में जीसीडी के साथ बहुत आसान है। एक विशिष्ट वर्कफ़्लो कुछ इस तरह होगा:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        // Perform async operation
        // Call your method/function here
        // Example:
        // NSString *result = [anObject calculateSomething];
                dispatch_sync(dispatch_get_main_queue(), ^{
                    // Update UI
                    // Example:
                    // self.myLabel.text = result;
                });
    });

GCD के बारे में अधिक जानकारी के लिए आप यहाँ Apple के प्रलेखन पर एक नज़र डाल सकते हैं


4

NSZombieEnabled को यह जानने में सक्षम करें कि किस ऑब्जेक्ट को रिलीज़ किया जा रहा है और फिर एक्सेस किया गया है। फिर जांच लें कि उसके getResultSetFromDB:साथ कुछ लेना-देना है या नहीं। यह भी देखें कि क्याdocids क्या अंदर कुछ है और अगर उसे बरकरार रखा जा रहा है।

इस तरह आप सुनिश्चित कर सकते हैं कि कुछ भी गलत नहीं है।


कृपया आपके द्वारा उपयोग की गई लाइन को कॉपी करें जो मुख्य धागे पर आसानी से चलती है।
निकोलस एस

मैं इसे मुख्य धागे से प्रयोग करता हूं और कम से कम दुर्घटनाग्रस्त होने के बजाय उस विधि को हिट करता हूं -[self getResultSetFromDB:docids];
श्रीकर अप्पाराजू

क्या आपने सक्षम किया है जो मैंने आपको बताया था?
निकोलस एस

इस पंक्ति में एक विराम बिंदु डालें: स्पॉटमैन * दर्पण = [[स्पॉटमाइन आवंटन] init]; और मुझे बताएं कि क्या इसकी हिट और, अगर तेहन, कौन सी रेखा दुर्घटनाग्रस्त हो जाती है। लाश को सक्षम करें ताकि हम एक स्पष्ट त्रुटि लॉग प्राप्त कर सकें।
निकोलस एस

हाँ, मैंने लाश को सक्षम किया है। मुझे यह मिलता है - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet रिलीज़]: डीललॉक्स्ड उदाहरण के लिए भेजा गया संदेश 0x2bff80 2011-08-14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): ऑब्जेक्ट 0x2c0cc0 की कक्षा __NSCFData ऑटोरेलिज्ड जिसके पास कोई पूल नहीं है - बस . Also when I try to call this method from background thread I do not reach SpotMain * मिरर को लीक करना ... ', यह जल्द ही बैकग्राउंड थ्रेड डालने के बाद क्रैश हो जाता है ...
Srikar Appalaraju

2

डिफ़ॉल्ट sqlite लाइब्रेरी जो iOS के साथ आती है पर SQLITE_THREADSAFE मैक्रो का उपयोग करके संकलित नहीं की जाती है। यह एक कारण हो सकता है कि आपका कोड क्यों क्रैश होता है।


2

स्विफ्ट 2.x उत्तर:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.