प्रश्न : माता-पिता के संदर्भ में बने परिवर्तनों को देखने के लिए मुझे अपना बच्चा संदर्भ कैसे मिलेगा ताकि वे UI को अपडेट करने के लिए मेरे NSFetchedResultsController को ट्रिगर करें?
यहाँ सेटअप है:
आपको एक ऐप मिला है जो बहुत सारे XML डेटा (लगभग 2 मिलियन रिकॉर्ड, प्रत्येक पाठ के सामान्य पैराग्राफ के आकार) को डाउनलोड और जोड़ता है। .sqlite फ़ाइल लगभग 500 एमबी आकार की हो जाती है। इस सामग्री को कोर डेटा में जोड़ने में समय लगता है, लेकिन आप चाहते हैं कि उपयोगकर्ता ऐप का उपयोग करने में सक्षम हो, जबकि डेटा स्टोर में डेटा को सामान्य रूप से लोड करता है। यह अदृश्य और उपयोगकर्ता के लिए अगोचर माना जाता है कि बड़ी मात्रा में डेटा चारों ओर ले जाया जा रहा है, इसलिए कोई लटका नहीं, कोई झटके नहीं: मक्खन की तरह स्क्रॉल। फिर भी, ऐप अधिक उपयोगी है, इसमें अधिक डेटा जोड़ा जाता है, इसलिए हम कोर डेटा स्टोर में डेटा को जोड़ने के लिए हमेशा इंतजार नहीं कर सकते। कोड में इसका मतलब है कि मैं वास्तव में आयात कोड में इस तरह कोड से बचना चाहूंगा:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
आईओएस 5 ऐप केवल इतना धीमा डिवाइस है जिसे यह समर्थन करने की आवश्यकता है कि यह एक iPhone 3GS है।
अपने वर्तमान समाधान को विकसित करने के लिए मैंने अब तक जिन संसाधनों का उपयोग किया है:
Apple के कोर डेटा प्रोग्रामिंग गाइड: कुशलता से डेटा आयात करना
- मेमोरी को डाउन रखने के लिए ऑटोरेलिज पूल का इस्तेमाल करें
- रिश्तों की कीमत। फ्लैट आयात करें, फिर अंत में रिश्तों को पैच अप करें
- यदि आप इसे मदद कर सकते हैं तो क्वेरी न करें, यह चीजों को ओ (एन ^ 2) तरीके से धीमा करता है
- बैचों में आयात करें: सहेजें, रीसेट करें, नाली करें और दोहराएं
- आयात पर पूर्ववत् प्रबंधक बंद करें
iDeveloper TV - कोर डेटा प्रदर्शन
- 3 संदर्भों का उपयोग करें: मास्टर, मुख्य और कारावास संदर्भ प्रकार
iDeveloper TV - Mac, iPhone और iPad अपडेट के लिए कोर डेटा
- PerformBlock के साथ अन्य कतारों पर रनिंग सेव करने से चीज़ें तेज़ होती हैं।
- एन्क्रिप्शन चीजों को धीमा कर देता है, यदि आप कर सकते हैं तो इसे बंद कर दें।
मार्कस ज़रा द्वारा कोर डेटा में बड़े डेटा सेट का आयात और प्रदर्शन
- आप वर्तमान रन लूप को समय देकर आयात को धीमा कर सकते हैं, इसलिए चीजें उपयोगकर्ता को सहज महसूस होती हैं।
- सैंपल कोड साबित करता है कि बड़े आयात करना संभव है और यूआई को उत्तरदायी बनाए रखना है, लेकिन 3 संदर्भों और डिस्क पर एसिंक्स की बचत के साथ तेज़ नहीं है।
मेरा वर्तमान समाधान
मुझे NSManagedObjectContext के 3 उदाहरण मिले हैं:
MasterManagedObjectContext - यह वह संदर्भ है जिसमें NSPersistentStoreCoordinator है और डिस्क पर सहेजने के लिए जिम्मेदार है। मैं ऐसा करता हूं इसलिए मेरी बचत अतुल्यकालिक हो सकती है और इसलिए बहुत तेज है। मैं इसे इस तरह लॉन्च करता हूं:
masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
mainManagedObjectContext - यह वह संदर्भ है जिसका यूआई हर जगह उपयोग करता है। यह MasterManagedObjectContext का बच्चा है। मैं इसे इस तरह से बनाता हूं:
mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[mainManagedObjectContext setUndoManager:nil];
[mainManagedObjectContext setParentContext:masterManagedObjectContext];
backgroundContext - यह संदर्भ मेरे NSOperation उपवर्ग में बनाया गया है जो XML डेटा को कोर डेटा में आयात करने के लिए जिम्मेदार है। मैं इसे ऑपरेशन की मुख्य विधि में बनाता हूं और इसे मास्टर संदर्भ से जोड़ता हूं।
backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[backgroundContext setUndoManager:nil];
[backgroundContext setParentContext:masterManagedObjectContext];
यह वास्तव में बहुत तेजी से काम करता है। बस इस 3 संदर्भ सेटअप को करके मैं 10x से अधिक अपनी आयात गति में सुधार करने में सक्षम था! ईमानदारी से, यह विश्वास करना मुश्किल है। (यह मूल डिजाइन मानक कोर डेटा टेम्पलेट का हिस्सा होना चाहिए ...)
आयात प्रक्रिया के दौरान मैं 2 अलग-अलग तरीकों से बचत करता हूं। प्रत्येक 1000 आइटम जो मैं पृष्ठभूमि के संदर्भ में सहेजता हूं:
BOOL saveSuccess = [backgroundContext save:&error];
फिर आयात प्रक्रिया के अंत में, मैं मास्टर / माता-पिता के संदर्भ पर बचत करता हूं, जो कि, मूल रूप से, मुख्य संदर्भ सहित अन्य बाल संदर्भों में संशोधनों को धक्का देता है:
[masterManagedObjectContext performBlock:^{
NSError *parentContextError = nil;
BOOL parentContextSaveSuccess = [masterManagedObjectContext save:&parentContextError];
}];
समस्या : समस्या यह है कि जब तक मैं दृश्य को लोड नहीं करता तब तक मेरा UI अपडेट नहीं होगा।
मेरे पास UITableView के साथ एक साधारण UIViewController है जिसे NSFetchedResultsController का उपयोग करके डेटा खिलाया जा रहा है। जब आयात प्रक्रिया पूरी हो जाती है, तो NSFetchedResultsController माता-पिता / मास्टर संदर्भ से कोई परिवर्तन नहीं देखता है और इसलिए UI स्वचालित रूप से अपडेट नहीं होता है जैसे मैं देखने के लिए उपयोग किया जाता हूं। यदि मैं UIViewController को स्टैक से पॉप करता हूं और इसे फिर से लोड करता हूं तो सभी डेटा है।
प्रश्न : माता-पिता के संदर्भ में बने परिवर्तनों को देखने के लिए मुझे अपना बच्चा संदर्भ कैसे मिलेगा ताकि वे UI को अपडेट करने के लिए मेरे NSFetchedResultsController को ट्रिगर करें?
मैंने निम्नलिखित कोशिश की है जो सिर्फ ऐप को लटकाता है:
- (void)saveMasterContext {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
NSError *error = nil;
BOOL saveSuccess = [masterManagedObjectContext save:&error];
[notificationCenter removeObserver:self name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
}
- (void)contextChanged:(NSNotification*)notification
{
if ([notification object] == mainManagedObjectContext) return;
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
return;
}
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}