2013-02-26 59 views
7

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

जाहिर NSFileProtectionNone का उपयोग करने जा इस को हल करने के लिए सबसे आसान तरीका होगा। मैं हालांकि नहीं करना चाहूंगा- मैं डेटाबेस में कुछ भी संवेदनशील संवेदनशील नहीं संग्रहीत कर रहा हूं, लेकिन ये स्थान अपडेट सुपर महत्वपूर्ण नहीं हैं।

मैं जानता हूँ कि मैं जाँच करने के लिए डेटा अभी तक अनलॉक किया गया है कि क्या [[UIApplication sharedApplication] isProtectedDataAvailable] उपयोग कर सकते हैं, और मैं अपने आवेदन प्रतिनिधि में applicationProtectedDataWillBecomeUnavailable: उपयोग कर सकते हैं एक बार उसे अनलॉक उचित प्रतिक्रिया करने। यह मेरे लिए गंदा लगता है, हालांकि-मैं अतिरिक्त चेकों की एक गुच्छा यकीन है कि कुछ भी नहीं करने के लिए जोड़ने के लिए गलत हो जाता है, तो लगातार की दुकान, फिर से सेटअप चीजों की एक गुच्छा एक बार यह उपलब्ध हो जाता है, और इतने पर उपलब्ध नहीं है। और वह अतिरिक्त कोड अधिक लाभ प्रदान नहीं करता है- ऐप अभी भी इस स्थिति में लॉन्च होने पर कुछ भी करने में सक्षम नहीं होगा।

तो मुझे लगता है कि मैं सिर्फ यकीन नहीं है जो इस से निपटने के लिए और अधिक "उचित" रास्ता है कर रहा हूँ:

  1. स्विच NSFileProtectionNone करने के लिए।
  2. अतिरिक्त जाँच में जोड़े बातों पर छोड़ने की सुविधा की दुकान उपलब्ध नहीं है, और applicationProtectedDataWillBecomeUnavailable: का उपयोग फिर से बातें स्थापित करने के लिए एक बार यह है।
  3. एप्लिकेशन पृष्ठभूमि ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) में शुरू की है और सुरक्षित डेटा उपलब्ध नहीं रहे ([[UIApplication sharedApplication] isProtectedDataAvailable] == NO)) बस exit(0) (या कुछ इसी तरह) एप्लिकेशन को छोड़ने की कहते हैं। एक ओर यह सबसे सरल समाधान की तरह लगता है, और मुझे वास्तव में कोई डाउनसाइड्स नहीं दिखता है। लेकिन यह भी लगता है ... "गलत"? मुझे लगता है कि मैं यह तय नहीं कर सकता कि यह एक साफ समाधान है या सिर्फ आलसी है। बाकी
  4. कुछ मैं सिर्फ के बारे में सोच नहीं कर रहा हूँ?

उत्तर

4

थोड़ी देर के लिए यह सोचने के बाद मैं एक समाधान के साथ आया हूं, मैं खुश हूं। exit(0) विकल्प के साथ विचार करने की एक बात यह है कि यदि डिवाइस को डिवाइस अनलॉक करने में कुछ समय लगता है, तो ऐप लगातार लोड हो रहा है, छोड़ रहा है, और पुनः लोड हो सकता है। जबकि यदि आप ऐप को बहुत कुछ करने से रोकते हैं, तो शायद इसे केवल एक बार लोड करना होगा, और अधिकतर अधिक कुशल होगा। इसलिए मैंने अपना विकल्प 3 आजमाने का फैसला किया और यह वास्तव में कितना गन्दा था। यह मैंने सोचा जितना आसान हो गया।

सबसे पहले मैं अपने ऐप प्रतिनिधि के लिए एक BOOL setupComplete संपत्ति गयी। यह मुझे यह देखने का एक आसान तरीका देता है कि ऐप को विभिन्न बिंदुओं पर पूरी तरह से लॉन्च किया गया था या नहीं। तब application:didFinishLaunchingWithOptions: में मैं प्रबंधित वस्तु संदर्भ प्रारंभ करने का प्रयास है, तो कुछ इस तरह करते हैं:

NSManagedObjectContext *moc = [self managedObjectContext]; 
if (moc) { 
    self.setupComplete = YES; 
    [self setupWithManagedObjectContext:moc]; 
} else { 
    UIApplication *app = [UIApplication sharedApplication]; 
    if ([app applicationState] == UIApplicationStateBackground && ![app isProtectedDataAvailable]) { 
     [app beginIgnoringInteractionEvents]; 
    } else [self presentErrorWithTitle:@"There was an error opening the database."]; 
} 

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

फिर applicationProtectedDataDidBecomeAvailable: में मैं कुछ इस तरह कहते हैं:

if (!self.setupComplete) { 
    NSManagedObjectContext *moc = [self managedObjectContext]; 
    if (moc) { 
     self.setupComplete = YES; 
     [self setupWithManagedObjectContext:moc]; 
     UIApplication *app = [UIApplication sharedApplication]; 
     if ([app isIgnoringInteractionEvents]) [app endIgnoringInteractionEvents]; 
    } else [self presentErrorWithTitle:@"There was an error opening the database."]; 
} 

सेटअप खत्म और इंटरफ़ेस को पुन: सक्षम है। यह सबसे अधिक काम है, लेकिन आपको यह सुनिश्चित करने के लिए अपने अन्य कोड को भी जांचना होगा कि कोर डेटा पर निर्भर कुछ भी आपके लगातार स्टोर से पहले कॉल हो रहा है। एक बात यह देखने के लिए है कि applicationWillEnterForeground और applicationDidBecomeActiveapplicationProtectedDataDidBecomeAvailable से पहले कॉल किया जा सकता है यदि उपयोगकर्ता इस पृष्ठभूमि स्थिति से ऐप लॉन्च करता है। इसलिए विभिन्न स्थानों पर मैंने if (self.setupComplete) { … } को यह सुनिश्चित करने के लिए जोड़ा है कि यह तैयार होने से पहले कुछ भी नहीं चलता है। मेरे पास कुछ स्थानों पर भी था जहां डेटाबेस लोड होने के बाद मुझे इंटरफ़ेस रीफ्रेश करने की आवश्यकता थी।

आदेश में (आंशिक रूप से) परीक्षा इस के आसपास ड्राइविंग का एक बहुत बिना, मैं अस्थायी रूप से संशोधित application:didFinishLaunchingWithOptions: डेटाबेस की स्थापना नहीं करने के लिए:

NSManagedObjectContext *moc = nil; // [self managedObjectContext]; 
if (moc) { 
    self.setupComplete = YES; 
    [self setupWithManagedObjectContext:moc]; 
} else { 
    UIApplication *app = [UIApplication sharedApplication]; 
    // if ([app applicationState] == UIApplicationStateBackground && ![app isProtectedDataAvailable]) { 
     [app beginIgnoringInteractionEvents]; 
    // } else [self presentErrorWithTitle:@"There was an error opening the database."]; 
} 

तब मैं अपने कोड applicationProtectedDataDidBecomeAvailable: में अधिक applicationWillEnterForeground: में ले जाया गया। इस तरह से मैं ऐप लॉन्च कर सकता हूं, सुनिश्चित करें कि कुछ भी अप्रत्याशित नहीं होता है, होम बटन दबाएं, ऐप खोलें, और सुनिश्चित करें कि सबकुछ काम कर रहा है। चूंकि वास्तविक कोड को एक महत्वपूर्ण दूरी को स्थानांतरित करने और हर बार पांच मिनट का इंतजार करने की आवश्यकता होती है, इसने मुझे यह अनुमान लगाने का एक अच्छा तरीका दिया कि क्या हो रहा था।

एक आखिरी चीज जिसने मुझे फिसल दिया वह मेरा लगातार स्टोर समन्वयक था।

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 
    if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator; 

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Test.sqlite"]; 

    NSError *error = nil; 
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    }  

    return _persistentStoreCoordinator; 
} 

यह शिथिल एप्पल के नमूना कोड है, जो टिप्पणी कि आप सही ढंग त्रुटि को संभालने की ज़रूरत में व्याख्या नहीं करता पर आधारित है: एक ठेठ कार्यान्वयन कुछ इस तरह लग सकता है। मेरा स्वयं का कोड इससे थोड़ा अधिक करता है, लेकिन एक बात जिसे मैंने नहीं सोचा था कि अगर लगातार स्टोर लोड करने में कोई त्रुटि हो, तो यह एक गैर-शून्य परिणाम देगा! यह मेरे सभी अन्य कोड को आगे बढ़ने की इजाजत दे रहा था जैसे कि यह सही तरीके से काम कर रहा था। और यहां तक ​​कि यदि लगातार स्टोर कोऑर्डिनेटर को फिर से बुलाया गया था, तो यह स्टोर को फिर से लोड करने की कोशिश करने के बजाय, एक वैध स्टोर के बिना, एक ही समन्वयक को वापस कर देगा। वहाँ विभिन्न तरीकों से आप इस समस्या से निपटने कर सकते हैं, लेकिन मेरे लिए यह नहीं सेट _persistentStoreCoordinator के लिए सबसे अच्छा लग रहा था जब तक कि यह दुकान को जोड़ने में सक्षम था:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 
    if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator; 

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Test.sqlite"]; 

    NSError *error = nil; 
    NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if ([coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 
     _persistentStoreCoordinator = coordinator; 
    } else { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    }  

    return _persistentStoreCoordinator; 
} 
+0

@robertspacer _persistentStoreCoordinator शून्य इस लाइन पर पर नहीं होगा: अगर ([_persistentStoreCoordinator addPersistentStoreWithType: NSSQLiteStoreType विन्यास: शून्य यूआरएल: storeURL विकल्प: शून्य त्रुटि: और त्रुटि]) { –

+0

@Glen टी हाँ, वह करना चाहिए समन्वयक का संदर्भ रहा है। फिक्स्ड। – robotspacer

0

मैं अनुभव किया है, आप जांच करने के लिए है कि

[[UIApplication sharedApplication] isProtectedDataAvailable] 

और इस प्रक्रिया

applicationProtectedDataWillBecomeUnavailable 

सुनिश्चित करें कि आप एक संरक्षित फ़ाइल का उपयोग नहीं करते हो।

managedObjectContext 

मेरे लिए काम नहीं किया।