কীভাবে এনএসউজারডেফাল্টগুলিতে কাস্টম অবজেক্টগুলি সঞ্চয় করা যায়


268

ঠিক আছে, তাই আমি কিছুটা ঘুরে বেড়াচ্ছি, এবং আমি আমার সমস্যাটি বুঝতে পারি, তবে কীভাবে এটি ঠিক করতে হয় তা আমি জানি না। আমি কিছু তথ্য ধরে রাখতে একটি কাস্টম ক্লাস করেছি। আমি এই শ্রেণীর জন্য অবজেক্ট তৈরি করি এবং সেশনগুলির মধ্যে তাদের শেষ হওয়া আমার দরকার। আমি আমার সমস্ত তথ্য wasোকানোর আগে NSUserDefaults, কিন্তু এটি কাজ করছে না।

-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.

আমি যখন আমার কাস্টম ক্লাস, "প্লেয়ার" ক্লাসে রাখি তখন আমি পেয়েছি ত্রুটি বার্তাটি NSUserDefaults। এখন, আমি পড়েছি যে দৃশ্যত NSUserDefaultsকেবল কিছু ধরণের তথ্য সঞ্চয় করে। তাহলে আমি কীভাবে আমার জিনিসগুলিতে প্রবেশ করব NSUSerDefaults?

আমি পড়েছি যে আমার কাস্টম অবজেক্টটি "এনকোড" করার এবং তারপর এটি প্রবেশের জন্য একটি উপায় থাকা উচিত, তবে আমি কীভাবে এটি বাস্তবায়িত করব তা নিশ্চিত নই, সহায়তা প্রশংসা হবে! ধন্যবাদ!

**** সম্পাদনা ****

ঠিক আছে, সুতরাং আমি নীচে প্রদত্ত কোডটি দিয়ে কাজ করেছি (আপনাকে ধন্যবাদ!), তবে আমি এখনও কিছু সমস্যা পেয়েছি। মূলত, কোডটি এখন ক্র্যাশ হয়ে গেছে এবং আমি কেন নিশ্চিত তা জানি না, কারণ এটি কোনও ত্রুটি দেয় না। সম্ভবত আমি বেসিক কিছু অনুপস্থিত এবং আমি খুব ক্লান্ত, কিন্তু আমরা দেখতে পাবেন। এখানে আমার কাস্টম ক্লাস, "প্লেয়ার" প্রয়োগ করা হচ্ছে:

@interface Player : NSObject {
    NSString *name;
    NSNumber *life;
    //Log of player's life
}
//Getting functions, return the info
- (NSString *)name;
- (int)life;


- (id)init;

//These are the setters
- (void)setName:(NSString *)input; //string
- (void)setLife:(NSNumber *)input; //number    

@end

বাস্তবায়ন ফাইল:

#import "Player.h"
@implementation Player
- (id)init {
    if (self = [super init]) {
        [self setName:@"Player Name"];
        [self setLife:[NSNumber numberWithInt:20]];
        [self setPsnCounters:[NSNumber numberWithInt:0]];
    }
    return self;
}

- (NSString *)name {return name;}
- (int)life {return [life intValue];}
- (void)setName:(NSString *)input {
    [input retain];
    if (name != nil) {
        [name release];
    }
    name = input;
}
- (void)setLife:(NSNumber *)input {
    [input retain];
    if (life != nil) {
        [life release];
    }
    life = input;
}
/* This code has been added to support encoding and decoding my objecst */

-(void)encodeWithCoder:(NSCoder *)encoder
{
    //Encode the properties of the object
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeObject:self.life forKey:@"life"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self = [super init];
    if ( self != nil )
    {
        //decode the properties
        self.name = [decoder decodeObjectForKey:@"name"];
        self.life = [decoder decodeObjectForKey:@"life"];
    }
    return self;
}
-(void)dealloc {
    [name release];
    [life release];
    [super dealloc];
}
@end

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

@class MainViewController;

@interface MagicApp201AppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    MainViewController *mainViewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) MainViewController *mainViewController;

-(void)saveCustomObject:(Player *)obj;
-(Player *)loadCustomObjectWithKey:(NSString*)key;


@end

এবং তারপরে বাস্তবায়ন ফাইলের গুরুত্বপূর্ণ অংশগুলি:

    #import "MagicApp201AppDelegate.h"
    #import "MainViewController.h"
    #import "Player.h"

    @implementation MagicApp201AppDelegate


    @synthesize window;
    @synthesize mainViewController;


    - (void)applicationDidFinishLaunching:(UIApplication *)application {
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        //First check to see if some things exist
        int startup = [prefs integerForKey:@"appHasLaunched"];
        if (startup == nil) {
//Make the single player 
        Player *singlePlayer = [[Player alloc] init];
        NSLog([[NSString alloc] initWithFormat:@"%@\n%d\n%d",[singlePlayer name], [singlePlayer life], [singlePlayer psnCounters]]); //  test
        //Encode the single player so it can be stored in UserDefaults
        id test = [MagicApp201AppDelegate new];
        [test saveCustomObject:singlePlayer];
        [test release];
}
[prefs synchronize];
}

-(void)saveCustomObject:(Player *)object
{ 
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
    [prefs setObject:myEncodedObject forKey:@"testing"];
}

-(Player *)loadCustomObjectWithKey:(NSString*)key
{
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSData *myEncodedObject = [prefs objectForKey:key ];
    Player *obj = (Player *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
    return obj;
}

আইই, সমস্ত কোড সম্পর্কে দুঃখিত। শুধু সাহায্য করার চেষ্টা করছি। মূলত, অ্যাপটি চালু হবে এবং তারপরে তাত্ক্ষণিকভাবে ক্রাশ হবে sh আমি এটিকে অ্যাপটির এনক্রিপশন অংশে সংকীর্ণ করেছি, যেখানে এটি ক্রাশ হয়ে গেছে, তাই আমি কিছু ভুল করছি তবে আমি নিশ্চিত নই কি। সাহায্য আবার প্রশংসা হবে, আপনাকে ধন্যবাদ!

(আমি এখনও ডিক্রিপ্ট করার মতো কাজ করতে পারি নি, কারণ আমি এখনও এনক্রিপ্ট করার কাজ করতে পারি নি))


আপনার কি স্ট্যাক ট্রেস বা ক্র্যাশ সম্পর্কে আরও তথ্য রয়েছে যেমন কোন লাইন নম্বরটি ক্র্যাশ ঘটায়? আমি তত্ক্ষণাত্ কোডটির সাথে কোনও ভুল দেখছি না, তাই একটি প্রারম্ভিক পয়েন্টটি সহায়ক হবে।
ক্রিসার

উপরের উদাহরণে আপনি নিজের জীবন সংরক্ষণের জন্য এনকোডঅজেক্ট ব্যবহার করেছেন যা একটি অন্তর্নিহিত। পরিবর্তে আপনার এনকোডইন্ট ব্যবহার করা উচিত।
ব্রুটটি

উত্তর:


516

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

- (void)encodeWithCoder:(NSCoder *)encoder {
    //Encode properties, other class variables, etc
    [encoder encodeObject:self.question forKey:@"question"];
    [encoder encodeObject:self.categoryName forKey:@"category"];
    [encoder encodeObject:self.subCategoryName forKey:@"subcategory"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    if((self = [super init])) {
        //decode properties, other class vars
        self.question = [decoder decodeObjectForKey:@"question"];
        self.categoryName = [decoder decodeObjectForKey:@"category"];
        self.subCategoryName = [decoder decodeObjectForKey:@"subcategory"];
    }
    return self;
}

পড়া এবং থেকে লেখা NSUserDefaults:

- (void)saveCustomObject:(MyObject *)object key:(NSString *)key {
    NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:encodedObject forKey:key];
    [defaults synchronize];

}

- (MyObject *)loadCustomObjectWithKey:(NSString *)key {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *encodedObject = [defaults objectForKey:key];
    MyObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
    return object;
}

কোডটি নির্লজ্জভাবে ধার করা হয়েছে: nsuserdefaults এ ক্লাস সংরক্ষণ করা


আমার পরিবর্তনগুলি প্রতিফলিত করতে উপরে আমার পোস্টটি সম্পাদনা করেছেন।
ইথান মিক

@ ক্রিসার আপনার এনএসউসারডেফাল্টস ডিফল্ট = [এনএসউসারডেফাল্টস স্ট্যান্ডার্ড ইউজারডেফাল্টস] এ ত্রুটি রয়েছে; ... NSUserDefaults * ডিফল্ট হওয়া উচিত।
ম্যাগি

2
এনএসকিডআরচিভার শিলা ... মনে হয় এটি স্বয়ংক্রিয়ভাবে এনএসআরায় বা এনএসডেটরিয় অবজেক্টে নেমে আসে এবং কোনও এনকোডেবল কাস্টম অবজেক্টের মধ্যে এনকোড করে।
BadPirate

2
আমি পেডেন্টিক হচ্ছি না, কেবল একটি আসল প্রশ্ন, এটা কি অ্যাপল নির্দেশিকাগুলির বিরুদ্ধে, সিন্থেসাইজড সেটারগুলি ব্যবহার করতে হবে, যেমন ইন.ডি. পদ্ধতিতে স্ব.প্রোপার্টি?
সম্মান সালাহউদ্দিন

2
@ chrissr দয়া করে এর NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];জন্য পরিবর্তন করুন NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];। ভেরিয়েবলগুলি মেলে না।
GoRoS

36

এনএসইউসারডেফাল্টসকে আরও সহজ এবং আরও সুবিধাজনক হিসাবে কাস্টম অবজেক্টটি সংরক্ষণ করতে সহায়তা করার জন্য আমি একটি লাইব্রেরি আরএমএমপ্পার ( https://github.com/roomorama/RMMapper ) তৈরি করি কারণ এনকোডউইথকোডার এবং ইনডিভিথকোডার বাস্তব বিরক্তিকর!

কোনও শ্রেণি সংরক্ষণাগারযোগ্য হিসাবে চিহ্নিত করতে কেবল ব্যবহার করুন: #import "NSObject+RMArchivable.h"

NSUserDephaults এ একটি কাস্টম অবজেক্ট সংরক্ষণ করতে:

#import "NSUserDefaults+RMSaveCustomObject.h"
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults rm_setCustomObject:user forKey:@"SAVED_DATA"];

NSUserDefaults থেকে কাস্টম আপত্তি পেতে:

user = [defaults rm_customObjectForKey:@"SAVED_DATA"]; 

আপনার লাইব্রেরিতে ধরে নেওয়া হয়েছে যে আপনি যা চালিয়ে যেতে চান তার জন্য আপনার সম্পত্তি রয়েছে এবং আপনি যা যা সম্পত্তি রেখেছেন তা স্থির রাখতে চান। যদি এটি সত্য হয় তবে আপনার গ্রন্থাগারটি অবশ্যই সহায়ক হতে পারে তবে আমি মনে করি আপনি এটি বেশিরভাগ ক্ষেত্রেই পাবেন না।
এরিক বি

কেবল প্লেইন অবজেক্টকে টিকিয়ে রাখতে এটি দরকারী, আমি বলব এর ব্যবহার জাভাতে জিসনের সাথে বেশ মিল। আপনি কিসের দিকে তাকিয়ে আছেন?
থমাসডাও

7
এটি সত্যিই সহায়ক ছিল, আমি উত্তরগুলি পড়তে পেরে খুশী হয়েছি; ডি
আলবারা

আমার কাস্টম অবজেক্টটির অন্য কাস্টম অবজেক্টটিতে কী আছে?
শিয়াল

@ শিয়াল: আপনি যদি অন্য কাস্টম অবজেক্ট সংরক্ষণাগারযোগ্য করে তুলেন তবে এটিও সংরক্ষণ হবে
থমাসডাও

35

সুইফট 4

কোডেবল প্রোটোকল প্রবর্তন করে যা এই ধরণের কাজের জন্য সমস্ত যাদু করে। আপনার কাস্টম স্ট্রাক্ট / শ্রেণিকে এটির সাথে সামঞ্জস্য করুন:

struct Player: Codable {
  let name: String
  let life: Double
}

এবং ডিফল্টগুলিতে সঞ্চয় করার জন্য আপনি প্রপার্টিলিস্ট এনকোডার / ডিকোডার ব্যবহার করতে পারেন :

let player = Player(name: "Jim", life: 3.14)
UserDefaults.standard.set(try! PropertyListEncoder().encode(player), forKey: kPlayerDefaultsKey)

let storedObject: Data = UserDefaults.standard.object(forKey: kPlayerDefaultsKey) as! Data
let storedPlayer: Player = try! PropertyListDecoder().decode(Player.self, from: storedObject)

এটি অ্যারে এবং এই জাতীয় সামগ্রীর অন্যান্য ধারক শ্রেণীর জন্যও এর মতো কাজ করবে:

try! PropertyListDecoder().decode([Player].self, from: storedArray)

1
কবজির মতো কাজ করে
নাথান ব্যারেটো

দ্রষ্টব্য যে আপনি কেবলমাত্র Codableনিখরচায় আচরণটি পাবেন যখন সমস্ত দৃষ্টান্তের সদস্যরা নিজেরাই Codable
বলপয়েন্টবিউন

1
বা বরং কেবল তাদের সদস্য প্রকারের সাথে সামঞ্জস্য করুন Codable। এবং তাই, পুনরাবৃত্তি। শুধুমাত্র খুব কাস্টম ক্ষেত্রে আপনার এনকোডিং কোড লিখতে হবে।
সের্গিউ টোডিরাস্কু

সুইফট 4. সঙ্গে সবচেয়ে সহজ উপায়
alstr

31

কেউ যদি একটি দ্রুত সংস্করণ খুঁজছেন:

1) আপনার ডেটা জন্য একটি কাস্টম ক্লাস তৈরি করুন

class customData: NSObject, NSCoding {
let name : String
let url : String
let desc : String

init(tuple : (String,String,String)){
    self.name = tuple.0
    self.url = tuple.1
    self.desc = tuple.2
}
func getName() -> String {
    return name
}
func getURL() -> String{
    return url
}
func getDescription() -> String {
    return desc
}
func getTuple() -> (String,String,String) {
    return (self.name,self.url,self.desc)
}

required init(coder aDecoder: NSCoder) {
    self.name = aDecoder.decodeObjectForKey("name") as! String
    self.url = aDecoder.decodeObjectForKey("url") as! String
    self.desc = aDecoder.decodeObjectForKey("desc") as! String
}

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(self.name, forKey: "name")
    aCoder.encodeObject(self.url, forKey: "url")
    aCoder.encodeObject(self.desc, forKey: "desc")
} 
}

2) নিম্নলিখিত ফাংশন ব্যবহার করে ডেটা সংরক্ষণ করতে:

func saveData()
    {
        let data  = NSKeyedArchiver.archivedDataWithRootObject(custom)
        let defaults = NSUserDefaults.standardUserDefaults()
        defaults.setObject(data, forKey:"customArray" )
    }

3) পুনরুদ্ধার করতে:

if let data = NSUserDefaults.standardUserDefaults().objectForKey("customArray") as? NSData
        {
             custom = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [customData]
        }

দ্রষ্টব্য: এখানে আমি কাস্টম শ্রেণীর অবজেক্টগুলির একটি অ্যারে সংরক্ষণ এবং পুনরুদ্ধার করছি।


9

@ ক্রিসারের উত্তর নেওয়া এবং এটির সাথে চলতে, এই কোডটি NSUserDefaultsকাস্টম অবজেক্টগুলি সংরক্ষণ এবং পুনরুদ্ধারে একটি দুর্দান্ত বিভাগে প্রয়োগ করা যেতে পারে :

@interface NSUserDefaults (NSUserDefaultsExtensions)

- (void)saveCustomObject:(id<NSCoding>)object
                     key:(NSString *)key;
- (id<NSCoding>)loadCustomObjectWithKey:(NSString *)key;

@end


@implementation NSUserDefaults (NSUserDefaultsExtensions)


- (void)saveCustomObject:(id<NSCoding>)object
                     key:(NSString *)key {
    NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
    [self setObject:encodedObject forKey:key];
    [self synchronize];

}

- (id<NSCoding>)loadCustomObjectWithKey:(NSString *)key {
    NSData *encodedObject = [self objectForKey:key];
    id<NSCoding> object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
    return object;
}

@end

ব্যবহার:

[[NSUserDefaults standardUserDefaults] saveCustomObject:myObject key:@"myKey"];

7

সুইফট 3

class MyObject: NSObject, NSCoding  {
    let name : String
    let url : String
    let desc : String

    init(tuple : (String,String,String)){
        self.name = tuple.0
        self.url = tuple.1
        self.desc = tuple.2
    }
    func getName() -> String {
        return name
    }
    func getURL() -> String{
        return url
    }
    func getDescription() -> String {
        return desc
    }
    func getTuple() -> (String, String, String) {
        return (self.name,self.url,self.desc)
    }

    required init(coder aDecoder: NSCoder) {
        self.name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
        self.url = aDecoder.decodeObject(forKey: "url") as? String ?? ""
        self.desc = aDecoder.decodeObject(forKey: "desc") as? String ?? ""
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.name, forKey: "name")
        aCoder.encode(self.url, forKey: "url")
        aCoder.encode(self.desc, forKey: "desc")
    }
    }

সংরক্ষণ এবং পুনরুদ্ধার করতে:

func save() {
            let data  = NSKeyedArchiver.archivedData(withRootObject: object)
            UserDefaults.standard.set(data, forKey:"customData" )
        }
        func get() -> MyObject? {
            guard let data = UserDefaults.standard.object(forKey: "customData") as? Data else { return nil }
            return NSKeyedUnarchiver.unarchiveObject(with: data) as? MyObject
        }

শুধু একটি অনুস্মারক: selfভেরিয়েবল সামনে বাধ্যতামূলক নয় initএবং encode
ট্যামস সেঞ্জেল

আপনি কীভাবে এনএসক্ডারের সাথে বস্তুটি অন্তর্নিহিত করছেন তা দেখাতে পারেন
অভিষেক

@ অভিষেক থাপলিয়াল, আমি আপনাকে বুঝতে পারি না। Init (aDecoder সংকেতপদ্ধতিরচয়িতা: NSCoder) এটি সূচনা
Vyacheslav

6

আপনি যে ডেটা / অবজেক্টটি এনএসউসারডেফাল্টসে সংরক্ষণ করেছেন তা সিঙ্ক্রোনাইজ করুন

-(void)saveCustomObject:(Player *)object
{ 
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
    [prefs setObject:myEncodedObject forKey:@"testing"];
    [prefs synchronize];
}

আশা করি এটা তোমাকে সাহায্য করবে। ধন্যবাদ


ভবিষ্যতের লোকদের মনে রাখবেন যে সুইফট 3 হিসাবে, "সিঙ্ক্রোনাইজ" আপনার কাছ থেকে একেবারেই কল করা উচিত নয়।
জোসে রামিরেজ

@ জোজেমাইট অ্যাপস কেন? অথবা আপনি কি এই বিষয়ের ব্যাখ্যা সহ একটি লিঙ্ক পোস্ট করতে পারেন?
কোড

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