NSMserDefaults में NSMutableArray में कस्टम ऑब्जेक्ट्स को संग्रहीत करना


101

मैं हाल ही में NSUserDefaults संग्रह में अपने iPhone ऐप के खोज परिणामों को संग्रहीत करने का प्रयास कर रहा हूं। मैं उपयोगकर्ता पंजीकरण जानकारी को सफलतापूर्वक सहेजने के लिए भी इसका उपयोग करता हूं, लेकिन किसी कारण से कस्टम लोकेशन कक्षाओं के मेरे NSMutableArray को संग्रहीत करने की कोशिश करना हमेशा खाली आता है।

मैंने NSMutableArray को एक NSData तत्व में इस पोस्ट के रूप में परिवर्तित करने की कोशिश की, लेकिन मुझे एक ही परिणाम मिलता है ( iPhone पर NSUserDefaults का उपयोग करके एक पूर्णांक सरणी को सहेजना संभव है? )

कोड के नमूने मैंने आजमाए हैं:

सहेजें:

[prefs setObject:results forKey:@"lastResults"];
[prefs synchronize];

या

NSData *data = [NSData dataWithBytes:&results length:sizeof(results)];
[prefs setObject:data forKey:@"lastResults"];

या

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results];
[prefs setObject:data forKey:@"lastResults"];

भार:

lastResults = (NSMutableArray *)[prefs objectForKey:@"lastResults"];

या

NSData *data = [prefs objectForKey:@"lastResults"];
memcpy(&lastResults, data.bytes, data.length);  

या

NSData *data = [prefs objectForKey:@"lastResults"];
lastResults = [NSKeyedUnarchiver unarchiveObjectWithData:data];

नीचे दी गई सलाह का पालन करने के बाद मैंने भी NSCoder को अपनी वस्तु में लागू कर दिया है (NSString के अति प्रयोग को अनदेखा करें):

#import "Location.h"


@implementation Location

@synthesize locationId;
@synthesize companyName;
@synthesize addressLine1;
@synthesize addressLine2;
@synthesize city;
@synthesize postcode;
@synthesize telephoneNumber;
@synthesize description;
@synthesize rating;
@synthesize priceGuide;
@synthesize latitude;
@synthesize longitude;
@synthesize userLatitude;
@synthesize userLongitude;
@synthesize searchType;
@synthesize searchId;
@synthesize distance;
@synthesize applicationProviderId;
@synthesize contentProviderId;

- (id) initWithCoder: (NSCoder *)coder
{
    if (self = [super init])
    {
        self.locationId = [coder decodeObjectForKey:@"locationId"];
        self.companyName = [coder decodeObjectForKey:@"companyName"];
        self.addressLine1 = [coder decodeObjectForKey:@"addressLine1"];
        self.addressLine2 = [coder decodeObjectForKey:@"addressLine2"];
        self.city = [coder decodeObjectForKey:@"city"];
        self.postcode = [coder decodeObjectForKey:@"postcode"];
        self.telephoneNumber = [coder decodeObjectForKey:@"telephoneNumber"];
        self.description = [coder decodeObjectForKey:@"description"];
        self.rating = [coder decodeObjectForKey:@"rating"];
        self.priceGuide = [coder decodeObjectForKey:@"priceGuide"];
        self.latitude = [coder decodeObjectForKey:@"latitude"];
        self.longitude = [coder decodeObjectForKey:@"longitude"];
        self.userLatitude = [coder decodeObjectForKey:@"userLatitude"];
        self.userLongitude = [coder decodeObjectForKey:@"userLongitude"];
        self.searchType = [coder decodeObjectForKey:@"searchType"];
        self.searchId = [coder decodeObjectForKey:@"searchId"];
        self.distance = [coder decodeObjectForKey:@"distance"];
        self.applicationProviderId = [coder decodeObjectForKey:@"applicationProviderId"];
        self.contentProviderId = [coder decodeObjectForKey:@"contentProviderId"];
    }
}

- (void) encodeWithCoder: (NSCoder *)coder
{
    [coder encodeObject:locationId forKey:@"locationId"];
    [coder encodeObject:companyName forKey:@"companyName"];
    [coder encodeObject:addressLine1 forKey:@"addressLine1"];
    [coder encodeObject:addressLine2 forKey:@"addressLine2"];
    [coder encodeObject:city forKey:@"city"];
    [coder encodeObject:postcode forKey:@"postcode"];
    [coder encodeObject:telephoneNumber forKey:@"telephoneNumber"];
    [coder encodeObject:description forKey:@"description"];
    [coder encodeObject:rating forKey:@"rating"];
    [coder encodeObject:priceGuide forKey:@"priceGuide"];
    [coder encodeObject:latitude forKey:@"latitude"];
    [coder encodeObject:longitude forKey:@"longitude"];
    [coder encodeObject:userLatitude forKey:@"userLatitude"];
    [coder encodeObject:userLongitude forKey:@"userLongitude"];
    [coder encodeObject:searchType forKey:@"searchType"];
    [coder encodeObject:searchId forKey:@"searchId"];
    [coder encodeObject:distance forKey:@"distance"];
    [coder encodeObject:applicationProviderId forKey:@"applicationProviderId"];
    [coder encodeObject:contentProviderId forKey:@"contentProviderId"];

}

जवाबों:


177

किसी सरणी में कस्टम ऑब्जेक्ट लोड करने के लिए, यह वही है जो मैंने सरणी को हथियाने के लिए उपयोग किया है:

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedArray"];
if (dataRepresentingSavedArray != nil)
{
    NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
    if (oldSavedArray != nil)
        objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
    else
        objectArray = [[NSMutableArray alloc] init];
}

आपको जांचना चाहिए कि उपयोगकर्ता डिफॉल्ट्स से लौटाया गया डेटा शून्य नहीं है, क्योंकि मेरा मानना ​​है कि एनआईएल से अनइंक्राइविंग दुर्घटना का कारण बनता है।

निम्नलिखित कोड का उपयोग करके संग्रह करना सरल है:

[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"];

जैसा कि f3lix ने बताया है, आपको अपने कस्टम ऑब्जेक्ट को NSCoding प्रोटोकॉल का अनुपालन करने की आवश्यकता है। निम्नलिखित तरीकों को जोड़कर चाल को करना चाहिए:

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

- (id)initWithCoder:(NSCoder *)coder;
{
    self = [super init];
    if (self != nil)
    {
        label = [[coder decodeObjectForKey:@"label"] retain];
        numberID = [[coder decodeIntegerForKey:@"numberID"] retain];
    }   
    return self;
}

3
आपको अपने initWithCoder के अंत में "रिटर्न सेल्फ" याद आ रहा था: विधि। लगता है कि जोड़ने के लिए जगह लेने के लिए अनुमति देता है।
ब्रैड लार्सन

2
आपको सरणियों को nsuserdefaults में संग्रहीत नहीं करना चाहिए क्योंकि सरणियाँ nususerdefaults के लिए बहुत बड़ी हो सकती हैं। इसके बजाय + (BOOL) के संग्रह में फ़ाइल को संग्रहीत किया जाना चाहिए। RootObject: (id) rootObject toFile: (NSString *) पथ। इस जवाब को इतना वोट क्यों दिया जाता है?
mskw

1
@mskw - आप इस बात में सही हैं कि NSUserDefaults का उपयोग बड़े सरणियों के भंडारण के लिए नहीं किया जाना चाहिए (इसके बजाय कोर डेटा या कच्ची SQLite का उपयोग किया जाना चाहिए), लेकिन यह एन्कोडेड ऑब्जेक्ट्स के छोटे सरणियों को स्टैस करने के लिए पूरी तरह से ठीक है। किसी भी मामले में, सवाल यह था कि यह कैसे करना है, जो उपरोक्त कोड प्रदान करता है। जहां तक ​​वोटों की बात है, आपका अनुमान उतना ही अच्छा है जितना मेरा। बहुत से लोग पिछले चार वर्षों में ऐसा करना चाहते हैं।
ब्रैड लार्सन

2
@ गुड्सम - नहीं, यह ठीक काम करता है। इसे आज़माएं, यह एक NSMutableArray को लौटाएगा जो वास्तव में परिवर्तनशील है। यह केवल वस्तुओं की उस सरणी को जोड़कर नया सरणी शुरू करता है।
ब्रैड लार्सन

1
@AlbertRenshaw - andSyncआपने ऊपर दिए गए कोड में कहां से जोड़ा? यह NSUserDefaults के लिए वास्तविक विधि हस्ताक्षर नहीं है। इसके अलावा, synchronize: नहीं के रूप में उपयोगी के रूप में यह एक बार किया गया है twitter.com/Catfish_Man/status/647274106056904704
ब्रैड लार्सन

13

मुझे लगता है कि आपने अपने initWithCoder विधि में एक त्रुटि प्राप्त की है, कम से कम प्रदान किए गए कोड में आप 'स्व' ऑब्जेक्ट को वापस नहीं करते हैं।

- (id) initWithCoder: (NSCoder *)coder
{
    if (self = [super init])
    {
        self.locationId = [coder decodeObjectForKey:@"locationId"];
        self.companyName = [coder decodeObjectForKey:@"companyName"];
        self.addressLine1 = [coder decodeObjectForKey:@"addressLine1"];
        self.addressLine2 = [coder decodeObjectForKey:@"addressLine2"];
        self.city = [coder decodeObjectForKey:@"city"];
        self.postcode = [coder decodeObjectForKey:@"postcode"];
        self.telephoneNumber = [coder decodeObjectForKey:@"telephoneNumber"];
        self.description = [coder decodeObjectForKey:@"description"];
        self.rating = [coder decodeObjectForKey:@"rating"];
        self.priceGuide = [coder decodeObjectForKey:@"priceGuide"];
        self.latitude = [coder decodeObjectForKey:@"latitude"];
        self.longitude = [coder decodeObjectForKey:@"longitude"];
        self.userLatitude = [coder decodeObjectForKey:@"userLatitude"];
        self.userLongitude = [coder decodeObjectForKey:@"userLongitude"];
        self.searchType = [coder decodeObjectForKey:@"searchType"];
        self.searchId = [coder decodeObjectForKey:@"searchId"];
        self.distance = [coder decodeObjectForKey:@"distance"];
        self.applicationProviderId = [coder decodeObjectForKey:@"applicationProviderId"];
        self.contentProviderId = [coder decodeObjectForKey:@"contentProviderId"];
    }

    return self; // this is missing in the example above


}

मैं उपयोग करता हूं

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results];
[prefs setObject:data forKey:@"lastResults"];

तथा

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"lastResults"];
if (dataRepresentingSavedArray != nil)
{
        NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
        if (oldSavedArray != nil)
                objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
        else
                objectArray = [[NSMutableArray alloc] init];
}

और यह मेरे लिए एकदम सही काम करता है।

सस्नेह,

स्टीफन


3
स्टेफ़न तुम जीवन रक्षक हो, यहाँ देखो; उस लाइन ने मेरे दिमाग को बचाया "अगर (स्व = [सुपर init])" stackoverflow.com/questions/1933285/…
fyasar

मुझे ERROR_BAD_ACCESS मिला लेकिन आपने मुझे बचा लिया। केवल बनाए रखने और स्वयं को जोड़ने के साथ संपत्ति का उपयोग कर रहा था।
डेविड

0

मुझे लगता है कि ऐसा लगता है कि आपके कोड की समस्या परिणाम सरणी को सहेज नहीं रही है। इसके लोडिंग डेटा का उपयोग करके देखें

lastResults = [prefs arrayForKey:@"lastResults"];

यह कुंजी द्वारा निर्दिष्ट सरणी वापस कर देगा।


0

देखें "क्यों NSUserDefaults iPhone SDK में NSMutableDictionary को बचाने में विफल रहा?" ( क्यों NSUserDefaults iPhone SDK में NSMutableDictionary को बचाने में विफल रहा? )


यदि आप कस्टम ऑब्जेक्ट्स को (डी) क्रमबद्ध करना चाहते हैं, तो आपको डेटा (एनएससी कोडिंग प्रोटोकॉल) को सीरीज़ (डी) करना होगा। समाधान आप अंतर सरणी के साथ काम करने के लिए संदर्भित करते हैं क्योंकि सरणी एक वस्तु नहीं है, लेकिन स्मृति का एक सन्निहित हिस्सा है।


मुझे लगता है कि आपका अधिकार मुझे NSCoding में दिखाई देगा (जब तक कि आपके पास एक अनुशंसित लिंकी नहीं है), ऑब्जेक्ट स्वयं NSStrings पर बने होते हैं, इसलिए मुझे लगता है कि मैं बस अपने खुद के सीरियललाइज़र लिख सकता हूं और उन सभी को एक स्ट्रिंग सरणी में डाल सकता हूं।
एंथनी मुख्य

ठीक है, इसलिए मैंने NSCode को ऊपर से लागू किया है, लेकिन अभी भी NSArchiver का उपयोग करके कोई खुशी नहीं है
एंथनी मेन

0

मैं इस तरह से सामान को स्टोर करने की कोशिश करने के खिलाफ सिफारिश करूँगा डिफॉल्ट में डीबी।

SQLite को चुनना और उपयोग करना काफी आसान है। मेरा एक स्क्रैनास्ट ( http://pragprog.com/screencasts/v-bdiphone) में एक एपिसोड है ) एक साधारण आवरण के बारे में जो मैंने लिखा था (आप एससी खरीदे बिना कोड प्राप्त कर सकते हैं)।

ऐप स्पेस में ऐप डेटा स्टोर करना ज्यादा साफ-सुथरा है।

सभी ने कहा कि अगर यह अभी भी इस डेटा को डिफॉल्ट्स डीबी में डालने के लिए समझ में आता है, तो पोस्ट को देखें।


1
सुझाव के लिए धन्यवाद, लेकिन मैं वास्तव में एसक्यूएल प्रश्नों को लिखना शुरू नहीं करना चाहता (जैसा कि मैं आपके उदाहरण में देखता हूं) बस कुछ तारों के साथ एक वस्तु के लिए
एंथनी मेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.