Save Customize Object by using UserDefault in objective C

Sellen Wei
3 min readJun 9, 2018

--

I have spend lots of time trying to find good tutorial online, but did not, after tried several hours myself, I finally get the idea how to save customize object in UserDefault in an easy way. Attach is my solution:

my customize class is little complicated (That is another reason why I struggling about how to save data in UserDefault):

I have two customize things, one class called userData, one protocol called user (bad name! but that is what it is in my company code database), just make it simple, let tell from the code:

@interface UserData ()@property (readwrite, strong, nonatomic, nullable) User * user;
@property (readwrite, strong, nonatomic, nonnull) customizeCache * myCache;
@end

and for User protocol, I have :

@interface User : NSObject <TBase, NSCoding> { //see I have NSCoding here, do not ignore it!!!!NSString * __firstName;NSString * __lastName;NSString * __emailAddress;NSString * __facebookID;NSString * __Uuid;BOOL __firstName_isset;BOOL __lastName_isset;BOOL __emailAddress_isset;BOOL __facebookID_isset;BOOL __Uuid_isset;}inside user.m- (void) encodeWithCoder: (NSCoder *) encoder{if (__firstName_isset){[encoder encodeObject: __firstName forKey: @"firstName"];}if (__lastName_isset){[encoder encodeObject: __lastName forKey: @"lastName"];}if (__emailAddress_isset){[encoder encodeObject: __emailAddress forKey: @"emailAddress"];}if (__facebookID_isset){[encoder encodeObject: __facebookID forKey: @"facebookID"];}if (__authResponse_isset){[encoder encodeObject: __authResponse forKey: @"authResponse"];}if (__status_isset){[encoder encodeObject: __status forKey: @"status"];}if (__hestanUuid_isset){[encoder encodeObject: __hestanUuid forKey: @"hestanUuid"];}
- (id) initWithCoder: (NSCoder *) decoder
{self = [super init];if ([decoder containsValueForKey: @"firstName"]){__firstName = [[decoder decodeObjectForKey: @"firstName"] retain_stub];__firstName_isset = YES;}if ([decoder containsValueForKey: @"lastName"]){__lastName = [[decoder decodeObjectForKey: @"lastName"] retain_stub];__lastName_isset = YES;}if ([decoder containsValueForKey: @"emailAddress"]){__emailAddress = [[decoder decodeObjectForKey: @"emailAddress"] retain_stub];__emailAddress_isset = YES;}if ([decoder containsValueForKey: @"facebookID"]){__facebookID = [[decoder decodeObjectForKey: @"facebookID"] retain_stub];__facebookID_isset = YES;}if ([decoder containsValueForKey: @"authResponse"]){__authResponse = [[decoder decodeObjectForKey: @"authResponse"] retain_stub];__authResponse_isset = YES;}if ([decoder containsValueForKey: @"status"]){__status = [[decoder decodeObjectForKey: @"status"] retain_stub];__status_isset = YES;}if ([decoder containsValueForKey: @"Uuid"]){__Uuid = [[decoder decodeObjectForKey: @"Uuid"] retain_stub];__Uuid_isset = YES;}return self;}}

beside this two things, I also have a login view controller, which I want to save user object when I click “log in” and in the future, I want user to log in without http request (check if user id exist in userDefault, if yes, I will skip login, I know this feature sounds crazy, why we have that?!!?)

but you got the idea, I need to save UserData into somewhere, and get the UserData later.

@implementation LogInViewController-(void)logIn {
NSData * userInNSDataType = [[NSUserDefaults standardUserDefaults] objectForKey:self.emailAddressTextField.text]; // get data from userdefault
User * user = [NSKeyedUnarchiver unarchiveObjectWithData:userData];if (user != nil) { //good skip check user info through HTTP
//do something, then go to next view controller
//I will not put my confidential code here!
}
else{ //ok, now I need to make http request and check user info
//make http request and make sure you got the callback
NSData * encodedUser = [NSKeyedArchiver archivedDataWithRootObject:[UserData getInstance].user]; // remember to transfer to NSData or even if you make customize class codable and write functions, error will happen
[[NSUserDefaults standardUserDefaults] setObject:encodedUser forKey:self.emailAddressTextField.text]; // save the data into somewhere[[NSUserDefaults standardUserDefaults] synchronize];
}

the concept here is, whenever we want to save an object, we transfer it to NSdata by using NSKeyedArchiver, then save to UserDefault. When we get the data, we get NSData first, and then transfer to our customize data by using NSKeyedUnarchiver

this is a very easy approach, no encode function need to write.

and there are two approach for this topic, I also attached here for future reference:

  1. may not work but for simple case you could use this: https://stackoverflow.com/questions/2315948/how-to-store-custom-objects-in-nsuserdefaults
  2. https://www.raywenderlich.com/1914/nscoding-tutorial-for-ios-how-to-save-your-app-data

--

--