2012-07-04 15 views
7

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

संक्षेप में, मुख्य स्क्रीन में एक तालिका दृश्य होता है, एक पंक्ति का चयन करने पर यह किसी अन्य तालिका दृश्य में सेग करता है जो चयनित पंक्ति के लिए मास्टर-विवरण फैशन में प्रासंगिक जानकारी प्रदर्शित करता है। अंतर्निहित डेटा दिन में एक बार वेब सेवा से JSON डेटा के रूप में पुनर्प्राप्त किया जाता है और फिर कोर डेटा स्टोर में कैश किया जाता है। SQLite डेटाबेस फ़ाइल को अनिश्चित काल तक बढ़ने से रोकने के लिए उस दिन से पहले का डेटा हटा दिया गया है। सभी डेटा दृढ़ता संचालन कोर डेटा का उपयोग करके किया जाता है, जिसमें NSFetchedResultsController विस्तार तालिका दृश्य को कम किया जाता है।

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

नीचे दी गई तालिका कि हो सकता है जब विस्तार तालिका दृश्य नियंत्रक लोड किया जाता है की घटनाओं के वास्तविक क्रम दिखाता है:

 
Main Thread       Background Thread 
viewDidLoad 

            Get JSON data (using AFNetworking) 

Create child NSManagedObjectContext (MOC) 

            Parse JSON data 
            Insert managed objects in child MOC 
            Save child MOC 
            Post import completion notification 

Receive import completion notification 
Save parent MOC 
Perform fetch and reload table view 

            Delete old managed objects in child MOC 
            Save child MOC 
            Post deletion completion notification 

Receive deletion completion notification 
Save parent MOC 

एक बार AFNetworking पूरा होने के ब्लॉक शुरू हो रहा है जब JSON डेटा आ गया है, एक नेस्टेड NSManagedObjectContext बनाई गई है और एक "आयातक" ऑब्जेक्ट को पास किया जो JSON डेटा को पार करता है और ऑब्जेक्ट को कोर डेटा स्टोर में सहेजता है। आयातक नए performBlock विधि iOS 5 में शुरू की का उपयोग कर कार्यान्वित:

NSManagedObjectContext *child = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    [child setParentContext:self.managedObjectContext];   
    [child performBlock:^{ 
     // Create importer instance, passing it the child MOC... 
    }]; 

आयातक वस्तु का मानना ​​है अपनी ही एमओसी के NSManagedObjectContextDidSaveNotification और फिर अपनी ही अधिसूचना जो विस्तार तालिका दृश्य नियंत्रक द्वारा मनाया जाता है पोस्ट। जब यह अधिसूचना पोस्ट की जाती है तो तालिका दृश्य नियंत्रक अपने (पैरेंट) एमओसी पर एक बचत करता है।

दिन के नए डेटा के आयात के बाद पुराने डेटा को हटाने के लिए मैं "डिलीटर" ऑब्जेक्ट के साथ एक ही मूल पैटर्न का उपयोग करता हूं। नए डेटा को प्राप्त किए गए परिणाम नियंत्रक द्वारा प्राप्त किए जाने के बाद यह असंकालिक रूप से होता है और विवरण तालिका दृश्य को पुनः लोड किया गया है।

एक चीज जो मैं नहीं कर रहा हूं वह किसी मर्ज नोटिफिकेशन को देख रहा है या किसी भी प्रबंधित ऑब्जेक्ट संदर्भ या लगातार स्टोर समन्वयक को लॉक कर रहा है। क्या यह कुछ मुझे करना चाहिए? मैं थोड़ा सा अनिश्चित हूं कि यह सब सही ढंग से कैसे आर्किटेक्ट करें ताकि किसी भी सलाह की सराहना की जा सके।

उत्तर

2

बस एक वास्तुशिल्प विचार:

द्वारा अपने निर्धारित डेटा ताज़ा पैटर्न के साथ

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

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

आगे चर्चा करने के लिए खुश ...

+0

मुझे यह विचार पसंद है, मुझे यह पसंद है ** बहुत **। यह भी लाभ है कि SQL डेटा फ़ाइल का एक फ़ाइल सिस्टम डिलीट ऑब्जेक्ट ग्राफ़ में प्रबंधित ऑब्जेक्ट को हटाए जाने से बहुत तेज़ होगा, हालांकि निश्चित रूप से वास्तव में विलोपन प्रदर्शन कोई फर्क नहीं पड़ता क्योंकि एक अलग निरंतर स्टोर होगा वैसे भी इस्तेमाल किया। मैं इस सप्ताह के अंत में इस दृष्टिकोण को जाने जा रहा हूं। –

3

पूर्व आईओएस 5, हम आम तौर पर दो NSManagedObjectContexts किया है। पृष्ठभूमि धागा डेटा लोड या हटा सकता है और फिर सहेज सकता है। परिणामी NSManagedObjectContextDidSaveNotification तब मुख्य थ्रेड पर पास किया गया था (जैसा कि आप कर रहे हैं)। हमने मुख्य धागे संदर्भ में लाने के लिए mergeChangesFromManagedObjectContextDidSaveNotification: कहा। यह हमारे लिए अच्छा काम किया है। इस के

एक महत्वपूर्ण पहलू यह है कि पृष्ठभूमि धागा ब्लॉक पर save: तक (... कि अधिसूचना को श्रोता से क्योंकि हम mergeChanges कहते हैं) मुख्य थ्रेड पर चल mergeChangesFromManagedObjectContextDidSaveNotification: पूर्ण होने के बाद। यह सुनिश्चित करता है कि मुख्य थ्रेड प्रबंधित ऑब्जेक्ट संदर्भ उन परिवर्तनों को देखता है। अगर आपको माता-पिता के बच्चे के रिश्ते हैं तो मुझे यह नहीं पता कि को की आवश्यकता है, लेकिन आपने पुराने मॉडल में विभिन्न प्रकार की परेशानी से बचने के लिए किया था।

मुझे यकीन नहीं है कि दो संदर्भों के बीच माता-पिता के संबंध होने का क्या फायदा है। यह आपके विवरण से लगता है कि डिस्क पर अंतिम सहेज मुख्य धागे पर होता है, जो शायद प्रदर्शन कारणों से आदर्श नहीं है। (विशेष रूप से यदि आप बड़ी मात्रा में डेटा हटा रहे हैं; हमारे ऐप्स में हटाने के लिए प्रमुख लागत हमेशा डिस्क पर अंतिम बचत के दौरान होती है।)

नियंत्रक दिखाई देने/गायब होने पर आप कौन सा कोड चल रहे हैं कोर डेटा परेशानी? आप किस प्रकार के स्टैक निशान पर दुर्घटना देख रहे हैं?

+0

धन्यवाद। मैं वास्तव में 'mergeChangesFromManagedObjectContextDidSaveNotification का उपयोग नहीं कर रहा हूं:' क्योंकि सामान्य उपयोग में नया डेटा इसके बिना बिल्कुल ठीक दिखाता है। हालांकि, मैंने इसे पिछले निर्माण में उपयोग किया है और दो स्क्रीन के बीच तेज़ी से स्विच करते समय भी यही क्रैश था। –

2

मुख्य मुद्दा मैं मल्टी-थ्रेडेड कोर डेटा अनजाने एक सूत्र में एक प्रबंधित वस्तु तक पहुँच रहा है के साथ किया है/एक यह में बनाया गया था के अलावा अन्य क़तार।

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

यह NSManagedObjectContext और NSManagedObject उपवर्गीकरण शामिल होगी:

  • एमओसी उपवर्ग के लिए एक इवर जोड़े और कतार इस पर बनाया गया था इसे करने के लिए आवंटित।
  • आपके एमओ सबक्लास को वर्तमान कतार की जांच करनी चाहिए जो इसकी एमओसी की कतार संपत्ति के समान है।

यह केवल कोड की कुछ लाइनें है, लेकिन लंबे समय तक आप त्रुटियों कि अन्यथा नीचे ट्रैक करने के लिए कड़ी मेहनत कर रहे हैं बनाने रोका जा सकता है।

+0

धन्यवाद, लेकिन मुझे यकीन नहीं है कि एमओसी की कतार कैसे प्राप्त करें क्योंकि इसे 'initWithConcurrencyType: NSPrivateQueueConcurrencyType' का उपयोग करके तत्काल किया जा रहा है जिसका अर्थ है कि यह अपनी निजी प्रेषण कतार बनाता है। –

+0

अपने प्रदर्शन के अंदर dispatch_get_current_queue के बारे में कैसे करें: –

+0

वह कतार निजी है; इसे सीधे एक्सेस करने का प्रयास करना कुछ ऐसा है जो ऐप्पल लोगों को एक बुरा विचार के रूप में बुलाता है। –

2

NSFetchedResultsController बड़े पैमाने पर हटाए जाने के लिए थोड़ा संवेदनशील साबित हुआ है, जहां मैं पहले खुदाई करना शुरू कर दूंगा।

मेरा प्रारंभिक प्रश्न यह है कि हटाए गए ऑपरेशन की शुरुआत से संबंधित टेबलव्यू का पुन: प्राप्त और पुनः लोड कैसे किया जाता है। क्या कोई मौका है कि विलोपन ब्लॉक बच्चे एमओसी को बचाएगा जबकि NSFetchedResultsController अभी भी ला रहा है या नहीं?

क्या यह संभव है कि जब आप विस्तृत दृश्य से मास्टर पर स्विच करें और फिर विस्तार से देखें तो कई समवर्ती पृष्ठभूमि कार्य चलेंगे?या फिर आप वेब सेवा से सभी डेटा को एक बार में केवल एक विशेष पंक्ति के लिए प्रासंगिक नहीं कर रहे हैं? इस और अधिक मजबूत बनाने के लिए

एक वैकल्पिक एक पैटर्न UIManagedDocument क्या उपयोग करता लिए इसी तरह उपयोग करने के लिए है:

मुख्य थ्रेड संगामिति प्रकार के रूप में एक माता पिता एमओसी उपयोग करने के बजाय, UIManagedDocument वास्तव में निजी कतार के रूप में मुख्य एमओसी बनाता है और बनाता है आपके लिए उपलब्ध मुख्य एमओसी मुख्य धागे पर उपयोग करें। यहां लाभ यह है कि पृष्ठभूमि में सभी I/O चलते हैं और माता-पिता को बचाता है एमओसी बच्चे एमओसी में हस्तक्षेप नहीं करता है जब तक कि बच्चे एमओसी स्पष्ट रूप से उनके बारे में नहीं जानता। ऐसा इसलिए है क्योंकि बचाओ बच्चे से माता-पिता में परिवर्तन करता है और दूसरी तरफ नहीं।

तो यदि आपने निजी कतार पर अपने हटाए गए निजी हैं, तो यह NSFetchedResultsController स्कोप में समाप्त नहीं होगा। और चूंकि यह पुराना डेटा है, यह वास्तव में पसंदीदा तरीका है।

मुख्य एमओसी (NSPrivateQueueConcurrencyType)

  • लगातार दुकान और पुराने डेटा को हटाने के लिए जिम्मेदार:

    एक वैकल्पिक मैं की पेशकश तीन संदर्भों का प्रयोग है।

बाल एमओसी एक (NSMainQueueConcurrencyType)

  • कुछ भी यूआई संबंधित और NSFetchedResultsController

बाल एमओसी बी के लिए जिम्मेदार (NSPrivateQueueConcurrencyType, बाल एमओसी एक के बच्चे)

  • नए डेटा डालने और इसे बाल एमओसी ए करने के लिए जिम्मेदार होने पर जिम्मेदार है।