क्यों NSUserDefaults iOS में NSMutableDictionary को बचाने में विफल रहा?


145

मैं किसी NSMutableDictionaryऑब्जेक्ट को सहेजना चाहूंगा NSUserDefaults। कुंजी प्रकार NSMutableDictionaryहै NSString, मान प्रकार है NSArray, जिसमें ऑब्जेक्ट की एक सूची होती है जो लागू होती है NSCoding। प्रति दस्तावेज़, NSStringऔर NSArrayदोनों के अनुरूप हैं NSCoding

मुझे यह त्रुटि मिल रही है:

[NSUserDefaults setObject: forKey:]: गैर-संपत्ति मूल्य सम्मिलित करने का प्रयास करें .... वर्ग NSCFDictionary के।

जवाबों:


230

मुझे एक विकल्प का पता चला, बचाने से पहले, मैं NSArrayउपयोग करते हुए रूट ऑब्जेक्ट ( ऑब्जेक्ट) को एनकोड करता हूं NSKeyedArchiver, जो समाप्त होता है NSData। तब UserDefaults का उपयोग करें को सहेजें NSData

जब मुझे डेटा की आवश्यकता होती है, तो मैं इसे पढ़ता हूं NSData, और ऑब्जेक्ट में वापस NSKeyedUnarchiverबदलने के लिए उपयोग करता हूं NSData

यह थोड़ा बोझिल है, क्योंकि मुझे NSDataहर समय / से कन्वर्ट करने की आवश्यकता है , लेकिन यह सिर्फ काम करता है।

यहाँ प्रति अनुरोध एक उदाहरण है:

सहेजें:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];

भार:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

सरणी में तत्व लागू होता है

@interface CommentItem : NSObject<NSCoding> {
    NSString *value;
}

फिर के कार्यान्वयन में CommentItem, दो तरीके प्रदान करता है:

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}

किसी के पास बेहतर उपाय है?

सबको धन्यवाद।


4
क्या आपके पास एक कोड नमूना है जिसे आप साझा कर सकते हैं, मैं इसे (537044) पोस्ट में करने की कोशिश कर रहा हूं लेकिन कोई खुशी नहीं है
एंथनी मुख्य

इसने मेरे लिए अच्छा काम किया। मैं एक NSArray वस्तुओं के NSArray को एनकोड करने की कोशिश कर रहा था जहाँ कुछ कीज़ स्ट्रिंग्स नहीं थीं। बस NSArray पर NSKeyedArchiver और Unarchiver का उपयोग करने से "गैर-संपत्ति मूल्य डालने का प्रयास" त्रुटि से छुटकारा मिल गया।
जॉन राइट

मुझे लोड की गई वस्तु को कब जारी करने की आवश्यकता है? कोई आबंटन नहीं कहा गया था, इसलिए मैं यह मान लूंगा कि यह निरंकुश है?
मार्क

7
हमें बचाने के लिए [
डिफॉल्ट्स

यहां पोस्ट किया गया समाधान कुछ समय के लिए काम कर सकता है, लेकिन जब आप कक्षा को हटाने या बदलने का निर्णय लेते हैं, तो आप खुद को गड़बड़ में बंद पाएंगे। एक बेहतर समाधान यह है कि अपनी वस्तु को NSNumbers, Strings इत्यादि का उपयोग करके अपने राज्य को डिक्शनरी में लिखें, फिर स्टोर करें। भविष्य दृढ़।
टॉम एंडरसन

105

यदि आप उपयोगकर्ता डिफॉल्ट्स में किसी ऑब्जेक्ट को सहेज रहे हैं, तो सभी ऑब्जेक्ट, पुनरावर्ती, सभी तरह से नीचे, संपत्ति सूची ऑब्जेक्ट होना चाहिए। NSCoding के अनुरूप होने का यहां कोई मतलब नहीं है - NSUserDefaultsस्वचालित रूप से उन्हें इनकोड नहीं किया जाएगा NSData, आपको खुद ऐसा करना होगा। यदि आपकी "ऑब्जेक्ट की सूची जो लागू होती है NSCoding" का अर्थ उन वस्तुओं से है जो संपत्ति की सूची ऑब्जेक्ट नहीं हैं, तो उपयोगकर्ता की चूक से बचाने से पहले आपको उनके साथ कुछ करना होगा।

FYI करें संपत्ति सूची वर्ग हैं NSDictionary, NSArray, NSString, NSDate, NSData, और NSNumber। आप NSMutableDictionaryउपयोगकर्ता की वरीयताओं के लिए उत्परिवर्ती उपवर्ग (जैसे ) लिख सकते हैं लेकिन आपके द्वारा पढ़ी गई वस्तुएँ हमेशा अपरिवर्तनीय रहेंगी।


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

मैं उसी समस्या को लेकर आया था, जब मैं NSURL को एक एनएसडीएल में एक वस्तु के रूप में संग्रहीत करना चाहता था और इसे एनएसयूज़रडिफॉल्ट्स में संग्रहीत करता था। मुझे इसे NSString में बदलना पड़ा, इससे काम किया।
निकेत्सला

1
महान! मेरे मामले में, मैंने NSNumber का उपयोग उपयोगकर्ता डिफ़ॉल्ट में NSDictionary की कुंजी के रूप में करने की कोशिश की। मुझे इसे NSString में बदलना होगा।
जॉय

1
इस तरह के मंद व्यवहार से अनुभवहीन कोडर अपने संपूर्ण डेटा मॉडल को उचित डेटा ऑब्जेक्ट बनाने के बजाय शब्दकोशों के रूप में लिखते हैं? Apple के लिए नींव की कक्षाएं लिखना कितना कठिन हो सकता है, जो इस तथ्य का उपयोग करता है कि obj-c में आत्मनिरीक्षण है और हमारे लिए बॉक्सिंग और अनबॉक्सिंग का ख्याल रखना है?
ArtOfWarfare 22

14

क्या शब्दकोश में आपकी सभी चाबियां हैं NSString? मुझे लगता है कि एक संपत्ति सूची में शब्दकोश को बचाने के लिए उन्हें होना चाहिए।


1
चाबियाँ NSString हैं। लेकिन मूल्य NSArray है, जिसका तत्व एक अनुकूलित वर्ग है जो NSCoding को लागू करता है। ऐसा प्रतीत होता है कि समाधान काम नहीं कर रहा है क्योंकि UserDefaults केवल 6 प्रकार के वर्ग का समर्थन करता है, NSCoding पर विचार नहीं करता है।
ब्लूडॉल्फिन

8

सरलतम उत्तर:

NSDictionaryकेवल एक वस्तु है , यदि कुंजी NSStrings है । तो, स्टोर "कुंजी" के रूप में NSStringके साथ stringWithFormat


उपाय :

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];

लाभ:

  1. यह स्ट्रिंग-मूल्य जोड़ देगा ।
  2. जब आपकी वैल्यू ऑफ वेरिएबल होगी तो यह Empty-Value जोड़ देगा NULL

2
मुझे एक समान समस्या थी: मेरी चाबियाँ NSNumbers थीं, जिन्हें स्पष्ट रूप से प्लिस्ट शब्दकोशों की कुंजियों में अनुमति नहीं है।
मार्क पौली

5

क्या आपने NSCodingप्रोटोकॉल को लागू करने पर विचार किया है ? यह आपको iPhone पर दो सरल तरीकों के साथ एन्कोड और डीकोड करने की अनुमति देगा जो इसके साथ कार्यान्वित किए जाते हैं NSCoding। सबसे पहले आपको NSCodingअपनी कक्षा में जोड़ना होगा ।

यहाँ एक उदाहरण है:

यह .h फ़ाइल में है

@interface GameContent : NSObject <NSCoding>

फिर आपको एनएसकोडिंग प्रोटोकॉल के दो तरीकों को लागू करने की आवश्यकता होगी।

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
               [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]];
        }
        return self;
    }

    - (void) encodeWithCoder: (NSCoder *)coder
    {
           [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"];
    }

अधिक जानकारी के लिए NSCoder पर प्रलेखन देखें। यह वास्तव में मेरी परियोजनाओं के लिए काम में आया है, जहां मुझे आवेदन बंद होने पर iPhone पर एप्लिकेशन की स्थिति को बचाने की आवश्यकता है और इसे वापस आने पर इसे वापस उसी स्थिति में पुनर्स्थापित करें।

कुंजी इंटरफ़ेस में प्रोटोकॉल जोड़ना है और फिर उन दो तरीकों को लागू करना है जो का हिस्सा हैं NSCoding

आशा है कि ये आपकी मदद करेगा!


0

कोई बेहतर उपाय नहीं है। एक अन्य विकल्प केवल कोडित ऑब्जेक्ट को डिस्क पर सहेजना होगा - लेकिन वही काम कर रहा है। वे दोनों NSData के साथ समाप्त होते हैं जो कि जब आप इसे वापस चाहते हैं तो डिकोड हो जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.