I am building an app where at login, the correct combination of username/password returns some basic user info (firstName, lastName, userType, companyID, etc).
I will be needing those values and strings throughout my application to retrieve user-specific data.
Could I store all those values and strings at login in an NSObject or NSData subclass so that I can later call it to retrieve the items I need? How can I do this? or is there a better alternative?
If you are just storing the data returned from a successful login like you say, First Name, Last Name etc. I would use NSUserDefaults.
If you intend to store any sensitive information such as username or password or anything else requiring additional confidentiality I would recommend using the keychain.
I would use Keychain since it is secure. Check this STKeychain
You can use NSUserDefaults. Create a User Model. Implement NSCoding protocol. Archive while storing and unarchive while fetching from NSUserDefaults.
#interface User: NSObject<NSCoding>
#property (nonatomic, copy) NSString *firstName;
#property (nonatomic, copy) NSString *lastName;
- (void)save;
+ (id)savedUser;
//User.m
#define kSavedUser #"SavedUser"
#pragma mark - Encoding
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.firstName forKey:#"FirstName"];
[encoder encodeObject:self.lastName forKey:#"LastName"]
}
#pragma mark - Decoding
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self)
{
_firstName = [decoder decodeObjectForKey:#"FirstName"];
_lastName = [decoder decodeObjectForKey:#"LastName"];
}
return self;
}
-(void)save
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
[defaults setObject:data forKey:kSavedUser];
[defaults synchronize];
}
+ (id)savedUser
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:kSavedUser];
if (data)
{
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
return nil;
}
+ (void)clearUser
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:kSavedUser];
[defaults synchronize];
}
Now you can create an instance of
User *user = [[User alloc]init];
user.firstName = #"";
user.lastName = #"";
[user save];
When you want to retrieve
User *user = [User savedUser];
EDIT:
If you want to clear the data, call the static method to remove saved user info
[User clearUser];
Related
language: Objective-C,
I'm new at iOS development so please guide me in a easiest way if you can, i'm saving data into dictionary then NSUserDefaults after that i want to get the data from they NSUserDefaults, I'm working when user clicked in a texfield then text should be stored into dictionary but when i check into Xcode after setting a break points dictionary shows nil. I'm sending screenshots and code please help me.
Thanks
initialization of dictionary in viewDidLoad
save to NSUserDefaults
-(void)textFieldDidEndEditing:(UITextField *)textField {
//we'll use the following method if the TF is out of the table means not in a cell.
if([textField isEqual:self.getNameLabel]){
[nameDateDict setObject:[textField text] forKey:K_NAME];
[self saveToNSUserDefaults];
}
}
Xcode-output
nameDateDict NSMutableDictionary * nil 0x0000000000000000
Sorry the name of texfield is getNameLabel, I'll edit it later so please don't confuse after reading the name.
Even that i've checked this code is working
[timeDict setObject:#"Hello" forKey:#"Greetings"];
[timeDict setObject:#"Bye" forKey:#"B_Key"];
[timeDict setObject:#"what?" forKey:#"W_Key"];
[[NSUserDefaults standardUserDefaults] setObject:timeDict forKey:#"Greetings"];
[[NSUserDefaults standardUserDefaults] setObject:timeDict forKey:#"B_Key"];
[[NSUserDefaults standardUserDefaults] setObject:timeDict forKey:#"W_Key"];
[[NSUserDefaults standardUserDefaults] synchronize];
timeDict = [[NSUserDefaults standardUserDefaults] objectForKey:#"Greetings"];
timeDict = [[NSUserDefaults standardUserDefaults] objectForKey:#"B_Key"];
timeDict = [[NSUserDefaults standardUserDefaults] objectForKey:#"W_Key"];
A couple of things are going on here. First, you have a scope problem, in that your create a local dictionary object in viewDidLoad, which you can't access later. It looks as though you'll want to have an NSMutableDictionary property available for the class, which should be designated either in the header file or interface extension in the implementation file (depending on your use of this dictionary in your project):
#property (nonatomic, strong) NSMutableDictionary *nameDateDictionary;
Second, you aren't correctly initializing or accessing your dictionary and it's objects. So, (using some literal syntax shortcuts) your viewDidLoad and saveToNSUserDefaults methods:
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *name = [defaults objectForKey:K_NAME];
NSDate *startDate = [defaults objectForKey:K_START_DATE];
NSDate *endDate = [defaults objectForKey:K_END_DATE];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:#{K_NAME: name,
K_START_DATE: startDate,
K_END_DATE: endDate}];
self.nameDateDictionary = dict;
}
- (void)saveToNSUserDefaults
{
NSMutableDictionary *dict = self.nameDateDictionary;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:dict[K_NAME] forKey:K_NAME];
[defaults setObject:dict[K_START_DATE] forKey:K_START_DATE];
[defaults setObject:dict[K_END_DATE] forKey:K_END_DATE];
[defaults synchronize];
}
- (BOOL)textFieldShouldReturn:(UITextField*)theTextField {
[theTextField resignFirstResponder];
return YES;
}
-(void) textFieldDidEndEditing:(UITextField *)textField {
[self saveToNSUserDefaults:#{#"keyName":textField.text}];
}
-(void)saveToNSUserDefaults:(NSDictionary *)dict{
[[NSUserDefaults standardUserDefaults] setObject:dict forKey:#"myDictionary"];
}
-(void *)retrieveFromNSUserDefaults{
NSDictionary *tempDict=[[NSDictionary alloc] initWithDictionary:[[NSUserDefaults standardUserDefaults] objectForKey:#"myDictionary"]];
NSlog(#"TextField Value: %#",[tempDict objectForKey:#"keyName"]);
}
The way you are storing the dictionary was not correct. Please go through the https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/index.html for more about how to use them.
Everyone came from a beginner's stage but try not to skip the basics.
As on your screenshots you are storing dictionary values in a wrong way, you store each time the whole dictionary to each NSUserDefaults key. It schoul be like that:
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:#"value" forKey:#"key"];
[[NSUserDefaults standardUserDefaults] setObject:[dict objectForKey:#"key"] forKey:#"key"];
To get back a value from NSUserDefaults to dictionary:
[dict setObject:[[NSUserDefaults standardUserDefaults] objectForKey:#"key"] forKey:#"key"];
PFQuery *Location = [PFQuery queryWithClassName:#"Location"];
[Location findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(#"%#", [objects objectAtIndex:0]);
}];
How can i store this object in NSUserDefaults?
For storing custom objects u need to add these two methods in your m file of custom object class
-(void)encodeWithCoder:(NSCoder *)encoder
{
//Encode the properties of the object
[encoder encodeObject:self.contact_fname forKey:#"contact_fname"];
[encoder encodeObject:self.contact_lname forKey:#"contact_lname"];
[encoder encodeObject:self.contact_image forKey:#"contact_image"];
[encoder encodeObject:self.contact_phone_number forKey:#"contact_phone_number"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if ( self != nil )
{
//decode the properties
self.contact_fname = [decoder decodeObjectForKey:#"contact_fname"];
self.contact_lname = [decoder decodeObjectForKey:#"contact_lname"];
self.contact_image = [decoder decodeObjectForKey:#"contact_image"];
self.contact_phone_number = [decoder decodeObjectForKey:#"contact_phone_number"];
}
return self;
}
then
-(void)writeArrayWithCustomObjToUserDefaults:(NSString *)keyName withArray:(NSMutableArray *)myArray
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:myArray];
[defaults setObject:data forKey:keyName];
[defaults synchronize];
}
-(NSArray *)readArrayWithCustomObjFromUserDefaults:(NSString*)keyName
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:keyName];
NSArray *myArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[defaults synchronize];
return myArray;
}
use these functions for storing and reading custom object arrays
or u could simply use this library https://github.com/roomorama/RMMapper
There is a constraint on what kind of objects can be stored in the user defaults, detailed on the Apple documentation page:
The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects. See What is a Property List? in Property List Programming Guide.
You will need to convert your array of objects to an array of dictionaries, one of the ways to achieve this is to implement a toDictionary method that will take all properties and put them into a dictionary.
You'll also need the reverse method, an initWithDictionary: if you'll also want to re-create the objects from the user defaults (you can use the converted dictionaries if you want, though).
Once you have the conversion methods, you can use the NSUserDefaults methods to store and retrieve the objects.
I am finding some problem while saving and retrieving data using nsuserdefaults.
What i want to do- iam accepting name and number from user from viewcontroller and saving it using nsuserdefault. when i click on save button i want to retrieve all the values from nsuserdefault and display it on tableview. now when i save the new data i want this data to get added to the existing data of nsuserdefault. can anyone help me with saving and retrieving nsuserdefault data.
----------MyCode---------------
nsuserdefaults *objdefault =[nsuserdefaults standarduserdefaults];
nameArray = [objdefault objectforkey:#"Name"];
[newNameArray addobject:txtName.text];
[nameArray addobject:newNameArray];
[objdefault setobject:nameArray forkey:#"Name"];
[objdefault synchronize];
all this saves and accepts null value
Please help. and thank you in advance
Use these methods to add name to NSUserDefaultsand get from NSUserDefaults
To add the name to NSUserDefaults call [self addNameToUserDefaults:#"abc"];
-(void)addNameToUserDefaults:(NSString *)name number:(NSString*)number{
NSUserDefaults *objdefault =[NSUserDefaults standardUserDefaults];
NSMutableArray *nameArray = [[objdefault objectForKey:#"NameAndNumber"] mutableCopy];
if(!nameArray)
nameArray = [#[] mutableCopy];
[nameArray addObject:#{#"name":name,#"number":number}];
[objdefault setObject:nameArray forKey:#"NameAndNumber"];
[objdefault synchronize];
}
To get all names from NSUserDefaults call NSMutableArray *names = [self getAllNames];
-(NSMutableArray *)getAllNames{
NSUserDefaults *objdefault =[NSUserDefaults standardUserDefaults];
return [[objdefault objectForKey:#"NameAndNumber"] mutableCopy];
}
It's not possible to add values for same in NSUSerDefaults. it will show you last value only. You should go for Core data or Sqlite. Still if you are not comfortable with that you can use plist to achieve this functionality.
This is what I have done in my project. You have to use NSMutableDictionary to add more value
- (void)addUserLocation:(NSString *)username location:(NSMutableDictionary *)location
{
NSString *currentUserKey = [NSString stringWithFormat:#"%#_%#", UserDefaultsKeyLocationData, username, nil];
NSMutableArray *oldData = [[NSMutableArray alloc]init];
if ([self loadUserLocation:username] != nil) {
oldData = [self loadUserLocation:username];
}
if (![oldData containsObject:location]) {
[oldData addObject:location];
}
[[NSUserDefaults standardUserDefaults] setObject:oldData forKey:currentUserKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (NSMutableDictionary *)loadUserLocation:(NSString *)username
{
NSString *currentUserKey = [NSString stringWithFormat:#"%#_%#", UserDefaultsKeyLocationData, username, nil];
return [[[NSUserDefaults standardUserDefaults] objectForKey:currentUserKey] mutableCopy];
}
If you want get all data. Please call loadUserLocation in your code
I am new in programming and i have one problem. I create app, with two views. First is tableviewcontroller and second is view controller. from second view i sending data into my tableview trough perepareForSegue method. My data (Strings) are NSMutableArray and this MutableArray i want to save into UsedDefault after my app didEnterBackgoung in appDelegate.m
Then i want to load it back, but nothing happened. I put my code in appDidBecomeActive in appDelegate.m and i already try write it in my first view viewDidLoad, but no action. My MuttableArray is still empty, after new app start.
here is my code:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSUserDefaults*defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.flipsideView.zoznamFunkcii forKey:#"NSMutableArray"];
[defaults synchronize];
}
flipsideView is my first View and zoznamFunkcii is my NSMuttable array
and this is my load method:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSUserDefaults*defaults = [NSUserDefaults standardUserDefaults];
self.flipsideView.zoznamFunkcii = [NSMutableArray arrayWithArray:[defaults objectForKey:#"NSMutableArray"]];
}
Can anyone help me with that? I don't know why it not work.
You are saving an empty NSMutableArray to NSUserDefaults. So of course the loaded array will be empty as well.
Here is your saving code with comments:
// overwrite zoznamFunkcii with empty array
self.flipsideView.zoznamFunkcii = [[NSMutableArray alloc]init];
NSUserDefaults*defaults = [NSUserDefaults standardUserDefaults];
// save this empty array to nsuserdefaults
[defaults setObject:self.flipsideView.zoznamFunkcii forKey:#"NSMutableArray"];
your saving code should probably look like this:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSUserDefaults*defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.flipsideView.zoznamFunkcii forKey:#"NSMutableArray"];
}
and because NSUserDefault does not save mutable objects your restoration code should look like this:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSUserDefaults*defaults = [NSUserDefaults standardUserDefaults];
self.flipsideView.zoznamFunkcii = [NSMutableArray arrayWithArray:[defaults objectForKey:#"NSMutableArray"]];
}
and if the objects inside your array are not instances of NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary you have to encode your array first. See this question for details on how to do that.
Here you can Save Object With NSUserDefault..
[[NSUserDefaults standardUserDefaults]setObject:[NSKeyedArchiver archivedDataWithRootObject:self.flipsideView.zoznamFunkcii] forKey:#"NSMutableArray"];
[[NSUserDefaults standardUserDefaults]synchronize];
and you make coder and decoder method
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.toolResult = [decoder decodeObjectForKey:#"obj1"];
self.toolNotes = [decoder decodeObjectForKey:#"obj2"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.toolResult forKey:#"obj1"];
[encoder encodeObject:self.toolNotes forKey:#"obj2"];
}
your Data Save Into NsuserDefault When you Get Data From NsUserDefault then you Use like
[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"NSMutableArray"]];
I have an NSMutableArray in which I store objects called "address". An address is an NSObject with 4-5 properties (NSStrings). The NSMutableArray shall contain a maximum of 15 address object.
What is the best way to store that array on the iPhone? Core data? NSUserDefaults? Should I maybe store every address object by itself, and not all objects in one NSMutableArray? In that case what should I do on the iPhone?
as #rog said, you may use NSUserDefaults to save data
& you should make your object follow protocal NSCoding
for examplem if you object is "YouObject"
#interface YouObject: NSObject {
}
#property (nonatomic, copy) NSString *uid;
#property (nonatomic, copy) NSString *name;
#end
//implement this 2 method
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.title = [decoder decodeObjectForKey:#"uid"];
self.author = [decoder decodeObjectForKey:#"name"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:title forKey:#"uid"];
[encoder encodeObject:author forKey:#"name"];
}
then archive or unarchive using NSUserDefaults
//archive
YouObject *object = [YouObject ....]
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object ];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"address"];
//unarchive
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"address"];
YouObject *object = (YouObject *)[NSKeyedUnarchiver unarchiveObjectWithData:data];
or if you have a YouObject Array, you can save the NSArray in the same way;
//archive
NSArray *addresses;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:address ];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"address"];
//unarchive
NSData *addressData = [[NSUserDefaults standardUserDefaults] objectForKey:#"address"];
NSArray *addresses = (NSArray*)[NSKeyedUnarchiver unarchiveObjectWithData:address];
For what you're describing, I think NSUserDefaults will suffice. See this post: How to store custom objects in NSUserDefaults. You can learn more about the limitations of NSUserDefaults here: What are the limitations of NSUserDefaults.
However, if you're saving/loading a large amount of data, then you should consider using Core Data.
Simplest way would to use the nsmutablearray read and write methods. All the data has to be plist data type nsarray nsdictionary nsstring nsnumber nsdate. Nsuserdefault like rog suggested is also good. As long as the amount of data remains small.