2009-10-29 13 views
5

मैं एक NSOperationQueue जो 2 NSOperations होता है और स्थापित करने setMaxConcurrentOperationCount 1.समस्याएं रकम जुटा समवर्ती एवं गैर समवर्ती NSOperations

संचालन से एक एक मानक गैर समवर्ती ऑपरेशन है (द्वारा एक के बाद उन्हें एक प्रदर्शन करने के लिए सेट कर दिया जाता है बस एक main विधि) जो वेब से कुछ डेटा (पाठ्यक्रम के अलग-अलग ऑपरेशन थ्रेड पर) को समकालिक रूप से पुनर्प्राप्त करता है। दूसरा ऑपरेशन एक समवर्ती ऑपरेशन है क्योंकि मुझे कुछ कोड का उपयोग करने की आवश्यकता है जिसे असीमित रूप से चलाना है।

समस्या यह है कि मैंने पाया है कि समवर्ती ऑपरेशन केवल तभी काम करता है जब इसे कतार में जोड़ा जाता है। यदि यह किसी भी गैर-समवर्ती परिचालन के बाद आता है, तो अजीब तरह से start विधि को ठीक कहा जाता है, लेकिन उस विधि के समाप्त होने के बाद और मैंने कॉलबैक के लिए अपना कनेक्शन सेटअप किया है, यह कभी नहीं करता है। कतार में कोई और संचालन निष्पादित नहीं किया जाता है। ऐसा लगता है कि यह प्रारंभ विधि रिटर्न के बाद लटकता है, और किसी भी यूआरएल कनेक्शन से कोई कॉलबैक नहीं कहा जाता है!

यदि मेरे समवर्ती ऑपरेशन को कतार में पहले रखा गया है तो यह सब ठीक काम करता है, एसिंक कॉलबैक काम करता है और इसके बाद के ऑपरेशन को पूरा होने के बाद निष्पादित किया जाता है। मैं बिल्कुल समझ में नहीं आता!

आप नीचे मेरे समवर्ती एनएसओपरेशन के लिए टेस्ट कोड देख सकते हैं, और मुझे पूरा यकीन है कि यह ठोस है।

किसी भी मदद की सराहना की जाएगी!

मुख्य थ्रेड अवलोकन:

मैं बस पता चला है कि अगर समवर्ती ऑपरेशन कतार पर पहला है तो [start] विधि मुख्य थ्रेड पर बुलाया जाता है। हालांकि, अगर यह कतार पर पहले नहीं है (यदि यह समवर्ती या गैर-समवर्ती के बाद है) तो [start] विधि मुख्य धागे पर नहीं बुलाया जाता है। यह महत्वपूर्ण लगता है क्योंकि यह मेरी समस्या के पैटर्न को फिट करता है। इसका क्या कारण रह सकता है?

समवर्ती NSOperation कोड:

@interface ConcurrentOperation : NSOperation { 
    BOOL executing; 
    BOOL finished; 
} 
- (void)beginOperation; 
- (void)completeOperation; 
@end 

@implementation ConcurrentOperation 
- (void)beginOperation { 
    @try { 

     // Test async request 
     NSURLRequest *r = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.google.com"]]; 
     NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:r delegate:self]; 
     [r release]; 

    } @catch(NSException * e) { 
     // Do not rethrow exceptions. 
    } 
} 
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 
    NSLog(@"Finished loading... %@", connection); 
    [self completeOperation]; 
} 
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 
    NSLog(@"Finished with error... %@", error); 
    [self completeOperation]; 
} 
- (void)dealloc { 
    [super dealloc]; 
} 
- (id)init { 
    if (self = [super init]) { 

     // Set Flags 
     executing = NO; 
     finished = NO; 

    } 
    return self; 
} 
- (void)start { 

    // Main thread? This seems to be an important point 
    NSLog(@"%@ on main thread", ([NSThread isMainThread] ? @"Is" : @"Not")); 

    // Check for cancellation 
    if ([self isCancelled]) { 
     [self completeOperation]; 
     return; 
    } 

    // Executing 
    [self willChangeValueForKey:@"isExecuting"]; 
    executing = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 

    // Begin 
    [self beginOperation]; 

} 

// Complete Operation and Mark as Finished 
- (void)completeOperation { 
    BOOL oldExecuting = executing; 
    BOOL oldFinished = finished; 
    if (oldExecuting) [self willChangeValueForKey:@"isExecuting"]; 
    if (!oldFinished) [self willChangeValueForKey:@"isFinished"]; 
    executing = NO; 
    finished = YES; 
    if (oldExecuting) [self didChangeValueForKey:@"isExecuting"]; 
    if (!oldFinished) [self didChangeValueForKey:@"isFinished"]; 
} 

// Operation State 
- (BOOL)isConcurrent { return YES; } 
- (BOOL)isExecuting { return executing; } 
- (BOOL)isFinished { return finished; } 

@end 

रकम जुटा कोड

// Setup Queue 
myQueue = [[NSOperationQueue alloc] init]; 
[myQueue setMaxConcurrentOperationCount:1]; 

// Non Concurrent Op 
NonConcurrentOperation *op1 = [[NonConcurrentOperation alloc] init]; 
[myQueue addOperation:op1]; 
[op1 release]; 

// Concurrent Op 
ConcurrentOperation *op2 = [[ConcurrentOperation alloc] init]; 
[myQueue addOperation:op2]; 
[op2 release]; 

उत्तर

10

मुझे पता चला कि समस्या क्या थी!

इन दो अमूल्य लेख डेव Dribin द्वारा विस्तार से समवर्ती आपरेशनों, साथ ही समस्याओं कि हिम तेंदुए & iPhone SDK परिचय जब चीजें एसिंक्रोनस रूप से है कि एक रन पाश की आवश्यकता होती है बुला वर्णन करते हैं। भी मुझे सही दिशा में इशारा करते हुए के लिए क्रिस Suter को

http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/ http://www.dribin.org/dave/blog/archives/2009/09/13/snowy_concurrent_operations/

धन्यवाद!

- (void)start { 

    if (![NSThread isMainThread]) { // Dave Dribin is a legend! 
     [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; 
     return; 
    } 

    [self willChangeValueForKey:@"isExecuting"]; 
    _isExecuting = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 

    // Start asynchronous API 

} 
+0

मुझे भी यही समस्या मिली। लेकिन मेरे मामले में स्टार्ट विधि को कभी-कभी नए जोड़े गए ऑपरेशन के लिए भी नहीं बुलाया जाता है। कतार अभी भी 'रनिंग' स्थिति दिखाती है। तो ऊपर विधि का उपयोग नहीं किया जा सकता है। क्या आप कोई अन्य समाधान जानते हैं? कृपया सहायता कीजिए.. –

0

मैं नोटिस नहीं किया था, और न ही मैं addDependency: का कोई उल्लेख देख पा रहे हैं, जो करने के लिए एक शर्त की तरह प्रतीत होता है उचित क्रम में निष्पादित करने के लिए संचालन प्राप्त करना।

संक्षेप में, दूसरा ऑपरेशन पहले पर निर्भर करता है।

+0

अरे हाँ मैं कतार कोड के बारे में उल्लेख करना भूल गया:

यह की जड़ यह सुनिश्चित करें कि start विधि हमें मुख्य थ्रेड पर कहा जाता है। मैंने कोई निर्भरता नहीं जोड़ा है, लेकिन किसी भी कारण से वास्तव में नहीं। सभी परिचालन असंबद्ध हैं, लेकिन मैं सिर्फ उन्हें एक के बाद एक चलाने के लिए चाहता हूँ। क्या निर्भरता मेरे पास होने वाली समस्या में कोई फर्क पड़ता है? मैंने setMaxConcurrentOperationCount को 1 पर सेट किया है और सोचा है कि यह पर्याप्त होगा। आपके प्रतिक्रिया के लिए धन्येवाद! –

+0

मैंने अभी निर्भरताएं जोड़ दी हैं और इसका मेरी समस्या पर कोई प्रभाव नहीं पड़ा है। –

6

आपकी समस्या NSURLConnection के साथ सबसे अधिक संभावना है। NSURLConnection किसी रन मोड पर चलने वाले रन लूप पर निर्भर करता है (आमतौर पर केवल डिफ़ॉल्ट वाले)।

  1. यकीन है कि यह ऑपरेशन केवल मुख्य थ्रेड पर चलाता करें:

    आपकी समस्या का समाधान की एक संख्या हैं। यदि आप ओएस एक्स पर ऐसा कर रहे थे, तो आप यह देखना चाहते हैं कि यह वही करता है जो आप सभी रन लूप मोड (जैसे मोडल और इवेंट ट्रैकिंग मोड) में चाहते हैं, लेकिन मुझे नहीं पता कि आईफोन पर क्या सौदा है।

  2. अपना खुद का धागा बनाएं और प्रबंधित करें। अच्छा समाधान नहीं है।

  3. कॉल - [NSURLConnection शेड्यूलइनरुन लूप: forMode:] और मुख्य थ्रेड या किसी अन्य थ्रेड में जो आप जानते हैं उसे पास करें। यदि आप ऐसा करते हैं, तो आप शायद कॉल करना चाहते हैं - [NSURLConnection unscheduleInRunLoop: forMode:] पहले अन्यथा आप एकाधिक थ्रेड में डेटा प्राप्त कर सकते हैं (या कम से कम यह दस्तावेज सुझाव देता है)।

  4. + [NSData डेटा WithContentsOfURL: विकल्प: त्रुटि:] जैसे कुछ का उपयोग करें और यह आपके ऑपरेशन को भी सरल बना देगा क्योंकि आप इसे इसके बजाय एक गैर-समवर्ती ऑपरेशन कर सकते हैं।

  5. # 4 पर संस्करण: उपयोग + [NSURLConnection sendSynchronousRequest: returningResponse: error:]।

यदि आप इससे दूर हो सकते हैं, तो # 4 या # 5 करें।

+0

आपकी प्रतिक्रिया के लिए धन्यवाद। मैंने जो कोड पोस्ट किया है वह एक साधारण उदाहरण है जिसे मैंने परीक्षण उद्देश्यों के लिए बनाया है। वास्तविक कार्यक्रम एक एपीआई का उपयोग कर रहा है जो मेरे नियंत्रण से बाहर है, और प्रकृति में असीमित है। हालांकि आपने मुझे 2 रोचक लेखों को दोबारा पढ़ने के लिए प्रेरित किया जिसने इस मुद्दे को हल किया है! मैं इसका जवाब दूंगा, इसलिए यह स्पष्ट है कि दूसरों के पास समस्या है लेकिन समय लेने के लिए धन्यवाद और आप रन लूप के बारे में सही हैं! –

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