2012-07-15 10 views
6

मैं एक आईपैड-ऐप विकसित कर रहा हूं और मैं वर्तमान में मल्टीथ्रेडिंग के लिए सर्वोत्तम दृष्टिकोण खोजने के लिए संघर्ष कर रहा हूं। मुझे इसे सरलीकृत उदाहरण के साथ चित्रित करने दें:
मेरे पास 2 सबव्यू, एक निर्देशिका पिकर और चयनित निर्देशिका में सभी छवियों के थंबनेल वाले गैलरी के साथ एक दृश्य है। चूंकि 'डाउनलोडिंग' और इन थंबनेल जेनरेट करने में काफी समय लग सकता है, मुझे मल्टीथ्रेडिंग की आवश्यकता है ताकि दृश्य की बातचीत और अद्यतन अवरुद्ध न हो।उद्देश्य सी में सर्वश्रेष्ठ बहुप्रचार दृष्टिकोण?

यह वही है मैं पहले से ही करने की कोशिश की है:
[आत्म performSelectorInBackground: @selector (displayThumbnails :) withObject: currentFolder];
यह ठीक काम करता है क्योंकि उपयोगकर्ता इंटरैक्शन अवरुद्ध नहीं होते हैं, हालांकि जब उपयोगकर्ता पहले फ़ोल्डर लोड हो रहा है तो उपयोगकर्ता किसी अन्य फ़ोल्डर पर टैप करता है तो यह दुर्भाग्य से विफल हो जाता है। दो धागे एक ही दृश्य और चर का उपयोग करने की कोशिश कर रहे हैं जिसके परिणामस्वरूप एक-दूसरे को उचित निष्पादन में गड़बड़ हो रही है। जब उपयोगकर्ता किसी अन्य फ़ोल्डर को टैप करते हैं, तो वर्तमान में लोड होने वाले फ़ोल्डर के displayThumbnails को निरस्त किया जाना चाहिए। मैं किसी भी तरह यह करने के लिए नहीं मिला ..

NSThreads
मैं इस कोशिश की, लेकिन लगभग एक ही समस्याओं के साथ संघर्ष किया पहली विधि के साथ के रूप में, मैं एक (आसान) जिस तरह से रद्द करने के लिए नहीं मिला चल रही विधि (हाँ, मुझे [aThread cancel] के बारे में पता है लेकिन धागे को 'फिर से शुरू करने' का कोई तरीका नहीं मिला। हो सकता है कि मुझे NSThread उप-वर्ग करना चाहिए और अपनी खुद की isRunning आदि विधियों को लागू करना चाहिए? लेकिन क्या कोई बेहतर तरीका या तीसरा (या यहां तक ​​कि चौथा और पांचवां) विकल्प नहीं है जो मैं देख रहा हूं?

मुझे लगता है कि यह एक काफी सरल उदाहरण है और मुझे लगता है कि शायद NSThread subclassing के बिना एक बेहतर समाधान है। तो आप क्या करेंगे? आपकी राय कृपया!

+4

स्पष्ट रूप से मैं ऐसा उत्तर नहीं दे सकता जो केवल "जीसीडी" – JustSid

+4

पढ़ता है आप इसके बारे में पूरी तरह से गलत हैं। गंभीरता से। – puzzle

+0

देखें [यहां] (https://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html%23//apple_ref/doc/uid/TP40008091-CH102-SW2) क्यों जीसीडी बहुत अच्छा है :) या इससे भी बेहतर, डब्ल्यूडब्ल्यूडीसी सत्रों में से एक देखें :) अपने मूल मुद्दे के बारे में: रद्द करने या रोकने के कई तरीके हैं, भले ही आप थ्रेड, जीसीडी या एनएसओपरेशनक्यूयू का उपयोग कर रहे हों। आप सो सकते हैं, निलंबित कर सकते हैं, लॉक पर इंतजार कर सकते हैं, पूरी तरह से रद्द कर सकते हैं। मुझे लगता है कि NSOperationQueue आपके लिए एक अच्छा समाधान होगा क्योंकि यह स्वचालित रूप से आपको उचित कार्यान्वयन के लिए मार्गदर्शन करता है .. – puzzle

उत्तर

6

NSOperationQueue इस कार्य के लिए अच्छी तरह से काम करना चाहिए।

एक और विकल्प सादा GCD होगा, हालांकि, यदि आपने कभी इसके साथ काम नहीं किया है, तो NSOperationQueue शायद बेहतर विकल्प है क्योंकि यह आपको "सही तरीके से" चीजों को लागू करने के लिए स्वचालित रूप से मार्गदर्शन करता है, इसमें रद्दीकरण के स्पष्ट तरीके हैं, आदि

5

आप पृष्ठभूमि में छवियों को डाउनलोड और संसाधित करने के लिए समवर्ती NSOperations का उपयोग करना चाहते हैं। इन्हें NSOperationsQueue द्वारा प्रबंधित किया जाएगा। अनिवार्य रूप से इन परिचालनों को प्रति छवि एक छवि लाने, इसे संसाधित करने, फ़ाइल सिस्टम में सहेजने के लिए कॉन्फ़िगर किया जाएगा, फिर छवि के मुख्य थ्रेड में मुख्य ऐप पर वापस संदेश भेजें।

गीथब पर कई परियोजनाएं हैं जिन्हें आप यह दिखाने के लिए देख सकते हैं कि यह कैसे करें - बस "समवर्ती" या "एनएसओपरेशन" का उपयोग करके जिथब खोजें।

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

तो आपको ब्लॉक, जीसीडी पर पढ़ने की आवश्यकता है, और उसके बाद कुछ ओपन सोर्स समवर्ती एनएसओपरेशंस कोड देखें। समवर्ती NSOperations का उपयोग करना ब्लॉक का उपयोग करने जितना आसान नहीं है।

0

अगर मैं इस समस्या थी, मैं शायद इस तरह एक दृष्टिकोण के लिए जाना होगा:

  • किसी एकल थ्रेड कि छवियों को लोड होगा, और परिणाम प्रदर्शित करने के मुख्य थ्रेड का कारण बनता है (मैं नहीं कर रहा हूँ एक जीयूआई ऑब्जेक्ट्स के साथ थ्रेड गड़बड़ होने का बड़ा प्रशंसक)

  • जब कोई नई निर्देशिका का अनुरोध किया जाता है ... अच्छा, यह इस बात पर निर्भर करता है कि आप चीजों को कैसे प्रबंधित करना चाहते हैं। असल में, एक मानक कतार निर्माण (हालत चर और सरणी) मुख्य धागे के लिए थ्रेड को बताने के लिए इस्तेमाल किया जा सकता है कि पथ पथ पारित करके "इस निर्देशिका की आवश्यकता होगी"; धागा कतार की जांच करेगा जब भी यह छवियों को लोड कर रहा है (जैसे प्रत्येक छवि या उसके बाद), और जब भी कोई

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

स्यूडोकोड:

while (forever) 
    new element = nil 
    if we have an active directory loader 
     tell directory loader to load one image 
     if false then make directory loader inactive 
     lock queue condition 
     if queue has elements 
      new element = retrieve LAST element (we aren't interested in the others) 
      empty queue 
      unlock with status "empty" 
     else 
      unlock queue 
    else 
     lock queue on condition "has elements" 
     new element = retrieve last element 
     empty queue 
     unlock with status "empty" 
    if new element != nil 
     if directory loader for new path does not exist 
      setup new directory loader for new path 
      store in dictionary 
      make it the "active" one 
     else 
      make the current one the "active" 

निर्देशिका लोडर का सवाल है, यह कुछ इस तरह दिख सकता है:

read one image: 
    if there are still images to read: 
     read, process and store one 
     return true 
    else 
     performSelectorOnMainThread with an "update GUI" method and the image list as parameter 
     return false; 

यह सिर्फ एक त्वरित स्केच है; धागे में कुछ कोड डुप्लिकेशंस है, और जिस तरह से मैंने इसे लिखा है, वे सभी छवियों को पढ़ने के बाद ही जीयूआई अपडेट करेंगे, उन्हें पढ़ने के बजाए उन्हें पढ़ने के बजाय। आपको वर्तमान छवि सूची की प्रतिलिपि बनाना होगा, या सिंक्रनाइज़ेशन जोड़ना होगा यदि आप ऐसा करना चाहते हैं।

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