2010-01-21 30 views
12

मैं NSOperation और ड्राइंग के उपयोग पर कुछ सलाह के बाद हूं:एनएसओपरेशन यूआई पेंटिंग ब्लॉक?

मेरे पास एक मुख्य धागा मेरा NSOperation सबक्लास बना है, जो उसके बाद इसे NSOperationQueue में जोड़ता है।

मेरा NSOperation कुछ भारी प्रसंस्करण करता है, यह अपने मुख्य() विधि में कई मिनटों के लिए लूप का इरादा रखता है, लगातार कुछ काम संसाधित करता है, लेकिन अभी के लिए मेरे पास थोड़ी देर() अंदर लूप है (1) अंदर, जो केवल 5 गुना (परीक्षण के लिए) के आसपास जाने के लिए सेट है।

मुख्य (मूल) थ्रेड जो इस NSOperation को स्पैन करता है वह यूआई को देखने और अपडेट करने के लिए ज़िम्मेदार है।

मेरा उद्देश्य एनएसओपरेशन थ्रेड को मुख्य थ्रेड को बताने के लिए एक अधिसूचना का उपयोग करना था, जिसने यह कुछ मात्रा में प्रसंस्करण किया था, इस समय जब यह अधिसूचना प्रत्येक बार() लूप (यानी; एक बार एक बार क्योंकि यह सिर्फ नींद कर रहा है (1))। मुख्य धागा (दृश्य), इन सूचनाओं को प्राप्त करने के लिए रजिस्टर करता है।

नोटिफिकेशन तुरंत मुख्य थ्रेड तक पहुंचते हैं, और अतुल्यकालिक लगते हैं, ठीक दिख रहे हैं। ऐसा प्रतीत होता है कि दोनों थ्रेड अपेक्षित के रूप में चलते हैं ... वह है - समवर्ती रूप से। (मैं एनएसएलओजी() का उपयोग केवल तभी जांचता हूं जब प्रत्येक धागा अधिसूचना भेजता है और प्राप्त करता है)।

जब दृश्य को अधिसूचना प्राप्त होती है, और इसकी हैंडलर विधि को कॉल किया जाता है, तो मैं बस एक पूर्णांक चर बढ़ाता हूं, और इसे देखने के लिए कोशिश करता हूं (पाठ्यक्रम की एक स्ट्रिंग के रूप में)। परीक्षण में, drawRect में कोड: स्क्रीन पर इस पूर्णांक (एक स्ट्रिंग के रूप में) खींचता है ठीक है।

हालांकि: यहां मेरी समस्या है (खेद है कि यहां आने में थोड़ी देर लग गई है): जब मुख्य धागा (देखें) एनएसओपरेशन से अधिसूचना प्राप्त करता है, तो यह इस परीक्षण पूर्णांक को अद्यतन करता है और [self setNeedsDisplay] को कॉल करता है। हालांकि, एनएसओपरेशन समाप्त होने तक दृश्य खुद को फिर से नहीं चलाता है! मुझे उम्मीद थी कि एनएसओपरेशन, एक अलग थ्रेड होने के कारण, मुख्य थ्रेड के ईवेंट लूप को अवरुद्ध करने की कोई क्षमता नहीं होगी, लेकिन ऐसा लगता है कि यह हो रहा है। जब एनएसओपरेशन खत्म हो जाता है और इसका मुख्य() रिटर्न मिलता है, तो दृश्य अंततः सीधे खुद को फिर से हटा देता है।

शायद मैं NSOperation सही ढंग से उपयोग नहीं कर रहा हूं। मैं इसे "गैर-समवर्ती" मोड में उपयोग कर रहा हूं, लेकिन नाम के बावजूद मेरी समझ यह है कि यह अभी भी एक नया धागा पैदा करता है और असीमित प्रक्रिया के लिए अनुमति देता है।

कोई मदद या सलाह बहुत सराहना की, अगर आप कुछ कोड देखना चाहते हैं तो बस मुझे बताएं।

उत्तर

10

आपकी अधिसूचना के जवाब में किए गए पर्यवेक्षक में विधि मुख्य धागे पर नहीं की जा रही है।

तो, उस विधि में, आप performSelectorOnMainThread:withObject:waitUntilDone: का उपयोग करके मुख्य धागे पर चलाने के लिए एक और विधि को मजबूर कर सकते हैं।

उदाहरण के लिए:

MyOperation.m

- (void)main { 
    for (int i = 1; i <= 5; i++) { 
     sleep(1); 
     [[NSNotificationCenter defaultCenter] postNotificationName:@"GTCNotification" object:[NSNumber numberWithInteger:i]]; 
    } 
} 

MyViewController.m

- (void)setupOperation { 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myNotificationResponse:) name:@"GTCNotification" object:nil]; 

    NSOperationQueue *opQueue = [[NSOperationQueue alloc] init]; 
    MyOperation *myOp = [[MyOperation alloc] init]; 

    [opQueue addOperation:myOp]; 

    [myOp release]; 
    [opQueue release]; 
} 

- (void)myNotificationResponse:(NSNotification*)note { 
    NSNumber *count = [note object]; 
    [self performSelectorOnMainThread:@selector(updateView:) withObject:count waitUntilDone:YES]; 
} 

- (void)updateView:(NSNumber*)count { 
    countLabel.text = count.stringValue; 
} 
+3

आप ऐसा कर सकते हैं (प्रदर्शन चयनकर्ताऑनमेन थ्रेड: withObject: waitUntilDone :) सीधे अगर आप चाहते हैं तो अपने NSOperation मुख्य विधि से - सभी अधिसूचना सामग्री के बिना। – grzaks

0

अधिकांश लोगों को पता है कि किसी भी प्रदर्शन से संबंधित कार्य मुख्य पर किया जाना चाहिए धागा।हालांकि, इसके प्रत्यक्ष परिणाम के रूप में, कोको बाइंडिंग संपत्ति में कोई भी परिवर्तन जो चित्र को प्रभावित कर सकता है उसे भी मुख्य धागे पर संशोधित किया जाना चाहिए (क्योंकि केवीओ ट्रिगर्स को थ्रेड पर संभाला जाएगा, जिससे वे ट्रिगर होते हैं)। यह ज्यादातर लोगों के लिए एक आश्चर्य है: विशेष रूप से, मुख्य धागे के अलावा किसी धागे से [स्वयं सेटडिड्सडिस्प्ले] को कॉल करना सुरक्षित नहीं है।

जैसा कि गेरी द्वारा उल्लिखित है, आपका एनएसएनोटिफिकेशन मुख्य धागे पर संसाधित नहीं होता है, इसे थ्रेड पर संसाधित किया जाता है, जिससे इसे भेजा जाता है। इसलिए आपके एनएसएनोटिफिकेशन हैंडलर में, आपको अपने आदेश वापस मुख्य थ्रेड पर भेजना चाहिए यदि वे डिस्प्ले से संबंधित हैं या यदि वे कोको बाइंडिंग को प्रभावित करते हैं। @performSelector काम करता है, लेकिन कतारों के साथ, मैं एक आसान और अधिक पठनीय विधि पाया है:

[ [ NSOperationQueue mainQueue] addOperationWithBlock:^(void) { 
    /* Your main-thread code here */ }]; 

यह एक माध्यमिक सहायक समारोह जिसका एकमात्र उद्देश्य है मुख्य धागे से कहा जाने की परिभाषा से बचा जाता है। mainQueue केवल> 10.6 में परिभाषित किया गया था।