NSUserDephaults এ একটি NSMutableArray এ কাস্টম অবজেক্টগুলি সংরক্ষণ করা


101

আমি সম্প্রতি আমার আইফোন অ্যাপ্লিকেশনটির অনুসন্ধান ফলাফলগুলি এনএসউসারডেফাল্টস সংগ্রহে সংরক্ষণ করার চেষ্টা করছি। আমি ব্যবহারকারীর নিবন্ধকরণ তথ্য সাফল্যের সাথে সংরক্ষণ করতে এটি ব্যবহার করি তবে কিছু কারণে আমার কাস্টম অবস্থানের ক্লাসগুলির NSMutableArray সবসময় খালি ফিরে আসে।

আমি এই পোস্ট হিসাবে NSMutableArray কে একটি NSData উপাদান হিসাবে রূপান্তর করার চেষ্টা করেছি কিন্তু আমি একই ফলাফল পেয়েছি ( আইফোনে NSUserDephaults ব্যবহার করে একটি পূর্ণসংখ্যা অ্যারে সংরক্ষণ করা সম্ভব? )

কোডের নমুনাগুলি আমি চেষ্টা করেছি:

সংরক্ষণ:

[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];

নীচের পরামর্শের পরে আমি আমার বস্তুতে এনএসকডারও প্রয়োগ করেছি (এনএসএসের অস্থায়ী ব্যবহারের অস্থায়ীতা উপেক্ষা করুন):

#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 হিসাবে উল্লেখ করা হয়েছে, আপনার নিজের কাস্টম অবজেক্টটি এনএসকোডিং প্রোটোকলকে মেনে চলতে হবে। নিম্নলিখিতগুলির মতো পদ্ধতি যুক্ত করার কৌশলটি করা উচিত:

- (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 এ সংরক্ষণ করা উচিত নয় কারণ অ্যারেগুলি nsuserdefaults এর জন্য খুব বড় হতে পারে। এটি পরিবর্তে + (BOOL) সংরক্ষণাগার রুটঅবজেক্ট: (আইডি) রুটঅবজেক্ট টু ফাইল: (এনএসএসআরটিং *) পাথ ব্যবহার করে কোনও ফাইলে সংরক্ষণ করা উচিত। এই উত্তর এত ভোট কেন?
এমএসকেডব্লিউ

1
@ এমএসকিউ - আপনি ঠিক বলেছেন যে এনএসউজারডেফাল্টগুলি বড় অ্যারে সংরক্ষণের জন্য ব্যবহার করা উচিত নয় (পরিবর্তে কোর ডেটা বা কাঁচা এসকিউএলাইট ব্যবহার করা উচিত) তবে সেখানে এনকোডযুক্ত বস্তুর ছোট অ্যারেগুলি স্ট্যাশ করা পুরোপুরি ঠিক আছে। যে কোনও ক্ষেত্রে, প্রশ্নটি এটি কীভাবে করবেন তা জিজ্ঞাসা করছিল যা উপরের কোডটি দেয়। যতদূর ভোট, আপনার অনুমান আমার মতই ভাল। গত চার বছরে প্রচুর লোক অবশ্যই এটি করতে চেয়েছিল।
ব্র্যাড লারসন

2
@ গুডসাম - না, এটি ঠিক কাজ করে। এটি ব্যবহার করে দেখুন, এটি এমন কোনও NSMutableArray ফিরিয়ে দেবে যা প্রকৃতপক্ষে পরিবর্তনযোগ্য। এটি কেবল নতুন অ্যারেটিকে এতে আইটেমের অ্যারে যুক্ত করে শুরু করে।
ব্র্যাড লারসন

1
@ অ্যালবার্ট রেনশওয়া - উপরের কোডটিতে andSyncআপনি যুক্ত করা কোথা থেকে এসেছে? এটি এনএসউসারডেফল্টসের জন্য কোনও আসল পদ্ধতির স্বাক্ষর নয়। এছাড়াও, 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

"এনএসউসারডেফল্টস আইফোন এসডিকে এনএসএমটেবলডেরিয়রিয়ান কেন সংরক্ষণ করতে ব্যর্থ হয়েছে ?" ( এনএসউজারডেফল্টস আইফোন এসডিকে এনএস মিউটেবাল ডিকোরিয়ালিটি সংরক্ষণ করতে কেন ব্যর্থ হয়েছিল? ) দেখুন


আপনি যদি কাস্টম অবজেক্টগুলিকে (ডি) ক্রমিকায়ন করতে চান, আপনাকে ডেটা (এনএসকোডিং প্রোটোকল) সিরিয়ালাইজ করতে (ডি) ফাংশন সরবরাহ করতে হবে। আপনি যে সমাধানটি উল্লেখ করেছেন তা ইন্টি অ্যারের সাথে কাজ করে কারণ অ্যারেটি কোনও বস্তু নয় তবে মেমরির সংলগ্ন অংশ।


আমি মনে করি আপনার ডানদিকে আমি এনএসকোডিং (আপনার প্রস্তাবিত লিঙ্কি না থাকলে) খতিয়ে দেখব, এনএসএসআরটিংগুলিতে সেগুলি নিজেই তৈরি করা হয় তাই আমি মনে করি আমি কেবল নিজের সিরিয়ালটি লিখতে পারি এবং সেগুলি সমস্ত স্ট্রিং অ্যারেতে রাখতে পারি
অ্যান্টনি মেইন

ঠিক আছে তাই আমি এনএসকোডটি উপরের দেখুনটি প্রয়োগ করেছি, তবে এনএসআরচিভার ব্যবহার করে এখনও কোনও আনন্দ নেই
অ্যান্টনি মেইন

0

আমি ডিফল্ট ডিবিতে এই জাতীয় জিনিস রাখার চেষ্টা করার বিরুদ্ধে সুপারিশ করব।

এসকিউএলাইট চয়ন এবং ব্যবহার করা মোটামুটি সহজ। আমার একটি স্ক্রিনকাস্টে ( http://pragprog.com/screencasts/v-bdiphone ) আমি লিখেছি এমন একটি সাধারণ মোড়কের একটি পর্ব রয়েছে (আপনি এসসি না কিনে কোডটি পেতে পারেন))

অ্যাপ্লিকেশন স্পেসে অ্যাপ্লিকেশন ডেটা সঞ্চয় করা এটি অনেক বেশি ক্লিনার।

যা যা বলেছিল তা যদি এখনও এই ডেটাটিকে ডিফল্ট ডিবি-তে রাখার অর্থ হয় তবে f3lix পোস্ট করা পোস্টটি দেখুন।


1
পরামর্শের জন্য ধন্যবাদ তবে আমি এসকিউএল কোয়েরিগুলি লিখতে শুরু করতে চাই না (যেমন আমি আপনার উদাহরণে দেখি) কেবল কয়েকটি স্ট্রিং সহ একটি বস্তুর জন্য
অ্যান্টনি মেইন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.