2015-03-27 14 views
6

मुझे क्या करना कोशिश कर रहा हूँ से टकराने के बिना: यूआई ठंड के बिनाबचत NSManagedObjectContext मुख्य थ्रेड

  • एक वेब एपीआई के साथ पृष्ठभूमि सिंक प्रदर्शन करते हैं। मैं MagicalRecord का उपयोग कर रहा हूं लेकिन यह वास्तव में इसके लिए विशिष्ट नहीं है।
  • यकीन है कि मैं संदर्भों का उपयोग कर रहा & सही ढंग से

ऐसी क्या मेरे सवाल का सच है: मेरी समझ सही है? इसके अलावा अंत में कुछ सवाल।

तो, MagicalRecord द्वारा उपलब्ध कराए गए संदर्भों हैं:

  • PrivateQueueConcurrencyType जो दुकान है, जो एक धीमी प्रक्रिया
  • की MR_defaultContext है करने के लिए डेटा लागू करने के लिए प्रयोग किया जाता है की MR_rootSavingContext MainQueueConcurrencyType
  • और पृष्ठभूमि के लिए आप एक संदर्भ जेनरेशन के साथ काम करना चाहते हैं

    • MR_saveToPersistentStoreWithCompletion: टेड MR_context द्वारा(), जो अब MR_defaultContext के बच्चा है और की है PrivateQueueConcurrencyType

    , एक अतुल्यकालिक तरह से बचाने के लिए, हम दो विकल्प हैं() जो MR_rootSavingContext तक सभी तरह से सहेज लेगा और डिस्क

  • MR_saveOnl पर सहेजें ySelfWithCompletion() जो केवल मूल संदर्भ तक ही बचाएगा (i? e। MR_defaultContext

वहां से एक संदर्भ MR_context के साथ बनाया) के लिए, मैंने सोचा कि मैं निम्नलिखित (इसे 1) यूआई ठंड के बिना # प्रयास कॉल कर सकता है:

let context = NSManagedObjectContext.MR_context() 
for i in 1...1_000 { 
    let user = User.MR_createInContext(context) as User 
    context.MR_saveOnlySelfWithCompletion(nil) 
} 
// I would normally call MR_saveOnlySelfWithCompletion here, but calling it inside the loop makes any UI block easier to spot 

लेकिन, मेरी धारणा थी गलत। मैं looked into MR_saveOnlySelfWithCompletion और देखा कि यह

[self performBlock:saveBlock]; 

जो according to Apple Docs

एसिंक्रोनस रूप से रिसीवर की कतार पर दिए गए ब्लॉक करता है पर निर्भर करता है।

तो मैं थोड़ा परेशान था, क्योंकि मैं उम्मीद करता हूं कि यह यूआई को अवरुद्ध न करें।

तो मैं करने की कोशिश की (के इसे कहते प्रयास # जाने 2)

let context = NSManagedObjectContext.MR_context() 
for i in 1...1_000 { 
    let user = User.MR_createInContext(context) as User 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {() -> Void in 
     context.MR_saveOnlySelfWithCompletion(nil) 
    } 
} 

और यह काम करता है, लेकिन यह सही नहीं लगता है।या performBlockAndWait: विधि यदि आपका कोड पहले से ही उस पर क्रियान्वित नहीं है

तब मैं जब एक कतार संघ के साथ बनाई गई एक संदर्भ को संदेश भेजने के लिए, आप performBlock का उपयोग करना चाहिए release notes of iOS 5.0

में कुछ पाया कतार ( मुख्य कतार प्रकार के लिए) या एक प्रदर्शन के दायरे के भीतर ... आमंत्रण (निजी कतार प्रकार के लिए)। उन विधियों को पारित ब्लॉक के भीतर, आप स्वतंत्र रूप से NSManagedObjectContext के तरीकों का उपयोग कर सकते हैं।

तो, मुझे लगता है कि यह सोचते हैं हूँ:

  • प्रयास # 1 यूआई जमा क्योंकि मैं वास्तव में मुख्य पंक्ति से और एक performBlock
  • प्रयास # के दायरे के भीतर नहीं यह फोन कर रहा हूँ 2 काम करता है, लेकिन मैं अपने आप ही पृष्ठभूमि धागा अभी तक एक और धागा बना रहा हूं संदर्भ पहले से ही है, जबकि

तो of course क्या मुझे क्या करना चाहिए उपयोग saveWithBlock है:

MagicalRecord.saveWithBlock { (localContext) -> Void in 
    for i in 1...1_000 { 
     User.MR_createInContext(context) 
    } 
} 

यह ऑपरेशन on a direct child of MR_rootSavingContext करता है जो PrivateQueueConcurrencyType का है। rootContextChanged के लिए धन्यवाद, MR_rootSavingContext तक जाने वाला कोई भी परिवर्तन MR_defaultContext पर उपलब्ध होगा।

तो ऐसा लगता है कि:

  • MR_defaultContext सही संदर्भ है जब यह इस तरह के एक के रूप में प्रदर्शित डेटा
  • संपादन अधिमानतः एक MR_context (MR_defaultContext के बच्चे) में किया जाता
  • लंबी चलने वाली कार्यों की बात आती है सर्वर सिंक को प्राथमिक रूप से saveWithBlock

क्या यह अभी भी नहीं मिलता है यह है कि MR_save [...] के साथ काम करने के लिए कैसे करें()। मैं इसे MR_context पर उपयोग करूंगा लेकिन चूंकि यह मेरे परीक्षण मामलों में मुख्य धागे को अवरुद्ध करता है, इसलिए मुझे यह नहीं दिखता कि यह कब प्रासंगिक हो जाता है (या जो मैंने याद किया ...)।

अपने समय के लिए धन्यवाद :)

उत्तर

5

ठीक है, मैं शायद ही कभी जादुई रिकॉर्ड उपयोग कर रहा हूँ, लेकिन जब से तुम ने कहा कि आप प्रश्न अधिक सामान्य है मैं एक जवाब का प्रयास करेंगे।

कुछ सिद्धांत: जब एक संदर्भ बनाने आप आप चाहते हैं कि क्या यह मुख्य या एक पृष्ठभूमि धागा

let context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType) 

द्वारा "बाध्य" से हमारा तात्पर्य है कि एक धागा द्वारा संदर्भित है पर बाध्य होने के लिए के रूप में एक संकेत पारित आंतरिक रूप से संदर्भ। ऊपर दिए गए उदाहरण में एक नया धागा बनाया गया है और संदर्भ के स्वामित्व में है। यह धागा स्वचालित रूप से नहीं किया जाता है, लेकिन स्पष्ट रूप से के रूप में बुलाया जाना चाहिए:

context.performBlock({() -> Void in 
    context.save(nil) 
    return 
}); 

तो 'dispatch_async' के साथ अपने कोड गलत है क्योंकि धागा संदर्भ ही है करने के लिए केवल संदर्भ से ही संदर्भित किया जा सकता है (यह है एक निजी धागा)।

क्या आप ऊपर से अनुमान लगाने के लिए किया है इस संदर्भ मुख्य थ्रेड के लिए बाध्य किया जाता है, performBlock बुला मुख्य थ्रेड से नहीं कुछ अलग करना होगा कि बुला संदर्भ तरीकों सीधे।

अंत में अपने बुलेट बिंदुओं पर टिप्पणी करने के: एक NSManagedObject संदर्भ यह बनाई गई है तक पहुँच जाना चाहिए ताकि यह है:

  • MR_defaultContext सही संदर्भ जब यह प्रदर्शित डेटा के लिए आता है वास्तव में केवल संदर्भ है कि आप UI से फ़ीड कर सकते हैं।

  • संपादन अधिमानतः एक MR_context (MR_defaultContext के बच्चे) में किया जाता: संपादित करता महंगा नहीं कर रहे हैं और आप ऊपर नियम का पालन करना चाहिए। यदि आप ऐसे फ़ंक्शन को कॉल कर रहे हैं जो मुख्य थ्रेड से एक NSManagedObject की गुणों को संपादित करता है (जैसे बटन के टैप पर) आपको मुख्य संदर्भ अपडेट करना चाहिए। दूसरी तरफ बचाता है महंगा और यही कारण है कि आपका मुख्य संदर्भ सीधे लगातार स्टोर से जुड़ा नहीं होना चाहिए, लेकिन इसके संपादन को लगातार एक सतत स्टोर के साथ पृष्ठभूमि समेकन के साथ रूट संदर्भ में धक्का दें।

  • सर्वर सिंक जैसे लंबे समय तक चलने वाले कार्यों को SaveWithBlock हां का उपयोग करके अधिमानतः किया जाता है।

अब, प्रयास 1

for i in 1...1_000 { 
    let user = User.MR_createInContext(context) as User 
} 
context.MR_saveOnlySelfWithCompletion(nil) 

में हर वस्तु निर्माण के लिए बचाने के लिए कोई जरूरत नहीं है। भले ही यूआई अवरुद्ध न हो, भले ही यह अपमानजनक हो।

MR_context के बारे में। जादुई रिकॉर्ड के लिए प्रलेखन में मुझे 'MR_context' नहीं दिखाई दे रहा है, इसलिए मैं सोच रहा हूं कि यह मुख्य संदर्भ तक पहुंचने का एक त्वरित तरीका है या नहीं। यदि ऐसा है, तो यह अवरुद्ध होगा।

+0

धन्यवाद, दिलचस्प जवाब। "हर वस्तु निर्माण के लिए बचाने की कोई ज़रूरत नहीं है।" - दरअसल, मैंने यह सुनिश्चित करने के लिए किया था कि मुख्य धागे पर कोई अवरोधन करना आसान होगा, मुझे इसका उल्लेख करना चाहिए था। MR_saveOnlySelfWithCompletion कॉल निष्पादन आंतरिक रूप से अवरोधित करें, यही कारण है कि मुझे समझ में नहीं आता कि यूआई अवरुद्ध क्यों है। – Nycen

+0

प्रदर्शनब्लॉक गारंटी नहीं देता है कि इसे पृष्ठभूमि थ्रेड पर निष्पादित किया जाएगा लेकिन धागे पर संदर्भ बाध्य है। यदि यह मुख्य संदर्भ है तो यह सामान्य रूप से अवरुद्ध होगा। असल में, लगता है कि मुख्य धागे पर, प्रदर्शन ब्लॉक के बाहर या अंदर एक संदर्भ विधि को कॉल करना वही है! तो सुनिश्चित करें कि आपका संदर्भ मुख्य नहीं है। (मैंने अपना जवाब संपादित किया) –

+1

जबकि आपका उत्तर शानदार है, मैं इस बात से असहमत हूं कि "हर ऑब्जेक्ट सृजन के लिए सहेजने की कोई ज़रूरत नहीं है।" ज्यादातर मामलों में यह सच हो सकता है, लेकिन यदि उस विशेष संदर्भ में आप संपादन कर रहे हैं तो अक्सर अन्य संदर्भों में परिवर्तनों को धक्का देना आवश्यक है, इसकी आवश्यकता हो सकती है। साथ ही साथ, जिन्हें आप पूर्ववत नहीं कर सकते हैं :) – Tim

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