How to save and retrieve NSObject class using NSUs

2020-04-17 03:29发布

Hi I want to save and retrieve NSObject class using NSUserDefaults for that I wrote below code but I am getting exception like below

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object for key DATA'

For saving :-

 SavingBean*savingbean = [[SavingBean alloc]init];
    [savingbean savingData:userName.text :passWord.text];

    NSUserDefaults * defaults = [[NSUserDefaults alloc]init];
    [defaults setObject:savingbean forKey:@"DATA"];

For retrieving:-

defaults = [[NSUserDefaults alloc]init];
savingbean = [defaults objectForKey:@"DATA"];

NSLog(@"Username is===>%@",savingbean.userName);
NSLog(@"Password is===>%@",savingbean.passWord);

ModelClas:-

.h file:-

#import <Foundation/Foundation.h>


@interface SavingBean : NSObject{

    NSString *userName;
    NSString *passWord;
}

@property(nonatomic, retain) NSString *userName;
@property(nonatomic, retain) NSString *passWord;

-(void)savingData :(NSString*)userName :(NSString*)password;

@end

.m file:-

#import "SavingBean.h"

@implementation SavingBean
@synthesize userName,passWord;

-(void)savingData :(NSString*)username :(NSString*)password{

    userName = username;
    passWord = password;
}

@end

2条回答
SAY GOODBYE
2楼-- · 2020-04-17 03:32

You can set object like this:

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:savingbean];
[currentDefaults setObject:data forKey:@"DATA"];
[currentDefaults synchronize];

and for get object like this:

NSData *data = [currentDefaults objectForKey:@"DATA"];
SavingBean *token = [NSKeyedUnarchiver unarchiveObjectWithData:data];

For Custom class you have to edit this methods in you bean class:

- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.userName==nil?@"":self.userName forKey: @"userName"];
    [encoder encodeObject:self.passWord==nil?@"":self.passWord forKey: @"passWord"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self = [super init];
    if(self)
    {
        self.userName = [decoder decodeObjectForKey: @"userName"];
        self.passWord = [decoder decodeObjectForKey: @"passWord"];
    }
    return self;
}

Here is most voted similar answer. You can also get good stuff from there.

You can also use JSON Accelerator to create bean class. This is very simple and powerful tool.

查看更多
做自己的国王
3楼-- · 2020-04-17 03:37

From good answer of Jayesh Thanki I tried sample from this question.I followed your coding.First I tried Save and Retrieve directly without encoder and decoder method.

For Save

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:savingbean];
[currentDefaults setObject:data forKey:@"DATA"];
[currentDefaults synchronize];

For Retrieve

NSData *data = [currentDefaults objectForKey:@"DATA"];
savingbean = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Now it shows error

[SavingBean encodeWithCoder:]: unrecognized selector sent to instance 0x7fc65940fc40

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SavingBean encodeWithCoder:]: unrecognized selector sent to instance 0x7fc65940fc40'

Then I googled most of the answer say

The NSCoding protocol declares the two methods that a class must implement so that instances of that class can be encoded and decoded. This capability provides the basis for archiving (where objects and other structures are stored on disk) and distribution (where objects are copied to different address spaces).

encodeWithCoder

encodeWithCoder: instructs the object to encode its instance variables to the coder provided; an object can receive this method any number of times.

initWithCoder

initWithCoder: instructs the object to initialize itself from data in the coder provided; as such, it replaces any other initialization method and is sent only once per object.

Then I understood that we must implement the encodeWithCoder and inintWithCoder first in NSObject Class.After that only we should save and retrieve the data.

->encoder is an archiver object
->decoder is an unarchiver object

Now First we have to implement the encodeWithCoder and initWithCoder in SavingBean.m

- (void)encodeWithCoder:(NSCoder *)encoder 
{
  //Encode properties, other class variables, etc
  [encoder encodeObject:@"AbhiRam" forKey:@"username"];
  [encoder encodeObject:@"Test@123" forKey:@"password"];
}

- (id)initWithCoder:(NSCoder *)decoder 
{
  if((self = [super init]))
  {
    //decode properties, other class vars
    userName = [decoder decodeObjectForKey:@"username"];
    passWord = [decoder decodeObjectForKey:@"password"];
  }
  return self;
}

Then in ViewController.m

For Save

SavingBean *savingbean = [[SavingBean alloc]init];
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:savingbean];
[currentDefaults setObject:data forKey:@"DATA"];
[currentDefaults synchronize];

For Retrieve

NSData *data = [currentDefaults objectForKey:@"DATA"];
savingbean = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Now when I run the application it does not show any error.It works fine now.

Why I give these things here is If anybody sees and tries this answer in some case they can get the error like above.So if they prefer two answer for this question they can very easily understand and get the solution very simply.

encodeWithCoder and initWithCoder of NSCoding

查看更多
登录 后发表回答