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.
Related
I have an array of custom objects which I want to store in array that updates the UITableView. The array is quite small ~10 objects at most. However, I discovered that I am unable to save an array of custom objects because:
Property list invalid for format: 200 (property lists cannot contain objects of type 'CFType')
2015-01-04 17:56:33.414 fanSyncDemo[13985:1264828] Attempt to set a non-property-list object (
It looks like I am going to have to turn the objects into NSData objects using NSKeyArchiver. However, I am having trouble understanding how this will look. Could someone help me with an example? My code for the saving looks like this:
- (IBAction)savePressed:(id)sender {
if (_NotificationsSegmentedControl.selectedSegmentIndex == 0){
_notificationBool = #"Yes";
}
else{
_notificationBool = #"No";
}
MyFavorite *favorite = [[MyFavorite alloc] initWithName:_nameFavoriteTextField.text withLocation:#"FANLOCATION" withIsOnNotificationsScreen:_notificationBool];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *favoritesList = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:#"favoritesList"]];
[favoritesList addObject:favorite];
[defaults setObject:favoritesList forKey:#"favoritesList"];
[defaults synchronize];
}
This is not a duplicate of this question because that example doesn't explain how to retrieve the data, nor can I figure out how to apply it to my example which normally I don't have a problem with but I have just been struggling with this.
From what I understand your going to want to do something like this in your MyFavorite class
- (id)initWithCoder:(NSCoder *)aDecoder
{
_location = [aDecoder decodeObjectForKey:#"location"];
_isOnNotificationsScreen = [aDecoder decodeObjectForKey:#"notificationScreen"];
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.location forKey:#"location"];
[aCoder encodeObject:self.isOnNotificationsScreen forKey:#"notificationScreen"];
}
I have an array that is broken down like this:
PersonArray
PersonObject
1. NSstring (personsName)
2. NSMutableArray (EventsObject)
I am able to save this array with the code below:
NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:mutableDataArray.count];
for (BC_Person *personObject in mutableDataArray)
{
NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject];
[archiveArray addObject:personEncodedObject];
}
NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
[userData setObject:archiveArray forKey:#"personDataArray"];
[userData synchronize];
What I am stuck on is: If I add an object to the NSMutableArray inside of the Person object, do I also have to turn that array of object (EventsObject) into NSData?
(I would assume I do, but I can't seem to figure out how to target that array of objects (EventsObject) to convert inside the PersonArray.
I hope I am explaining this in a manner that is easy to understand.
NSArray and some other classes implement the NSCoding protocol. So you can simplify your code to:
NSData *personData = [NSKeyedArchiver archivedDataWithRootObject:mutableDataArray];
NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
[userData setObject:personData forKey:#"personDataArray"];
[userData synchronize];
And for any objects to be archived you implement the NSCoding protocol. So for BC_Person it could look like this (I do not know the class so I am making up some properties as an example):
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.firstName forKey:#"firstName"];
[encoder encodeObject:self.lastName forKey:#"lastName"];
[encoder encodeObject:self.eventObjects forKey:#"eventObjects"];
}
In this example self.eventObjects would be an array of objects of your EventsObject class. The array knows how to encode itself, and for EventsObject you implement another -encodeWithCoder: method.
And to unarchive you reverse the process.
I tried to save an NSDictionary in NSUSerDefaults, but I get the following error:
Attempt to insert non-property value
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if(defaults) {
[defaults setBool: YES forKey: #"disableGetStarted"];
[defaults setObject: [json mutableCopy] forKey: #"user"];
[defaults synchronize];
NSLog(#"defaults %#", [defaults objectForKey: #"user"]);
}
Where json is an NSDictionary.
What can I do?
json may be a dictionary but all of the contents of the dictionary must be legal values to be stored in user defaults. All must be instances of: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.
If you only store standard objects inside the dictionary like NSData, NSString, NSNumber, NSDate, NSArray, NSDictionary or a combination of them you don't have to do anything special.
However, if you have instances of custom objects in it (i.e. classes that you've created) you first need to convert it into a compatible type (e.g. NSData). You can do this using the code below:
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:json];
[NSUserDefaults standardUserDefaults] setObject:data forKey:#"user"]
For this method to work, you ned to implement these 2 methods in the custom classes you are trying to save:
- (id)initWithCoder:(NSCoder*)coder
- (void)encodeWithCoder:(NSCoder*)coder;
To get the dictionary back from NSUserDefaults (decode) you can use:
NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:#"user"];
NSDictionary* json = [NSKeyedUnarchiver unarchiveObjectWithData:data];
EDIT
To check if your json object contains any [NSNull null] values, add this piece of code before you are making your insert into NSUserDefaults
for (id val in [json allValues])
{
if ([val isKindOfClass:[NSNull class]])
{
NSLog(#"This bad! NSNull should not be in the dictionary");
break;
}
}
If you get any This is bad... messages in the console, then you have 2 choices.
1. Use the archiving/unarchiving method I described above
2. Replace the NSNull objects from the dictionary with other values (e.g. empty strings) if this does not break your code.
One or more of the objects in your dictionary are not NSString, NSArray, NSDictionary, NSDate or NSData, the only objects that may be present. This code may help, it gives you more details why your dictionary is not valid:
- (BOOL)isValidPropertyList:(id)object {
//
// Check if `object` is a valid property list.
//
// # Return Value
// `YES` if the receiver is a valid property list, `NO` otherwise.
//
// # Discussion
// Intended to be called on NSArray and NSDictionary object to verify if the
// receiver is a valid property list. Will emit a description of any
// detected error.
//
NSData *xmlData;
NSString *error;
xmlData=[NSPropertyListSerialization
dataFromPropertyList:object
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error
];
if(xmlData)
{
return YES;
}
else
{
NSLog(#"Tested object is not a valid property list: %#",error);
}
return NO;
}
NSDictionary *dict = [[NSDictionary alloc] init];
dict = json;
[NSUserDefaults standardDefaults] setObject:dict forKey:#"user"];
NSUserDefaults doesn't distinguish between mutable and immutable objects, so when you get it back it'll be immutable. So if you make a mutable dictionary by chance ->
[[NSUserDefaults standardDefaults] setObject:dict forKey:#"user"] mutableCopy];
All objects of the dictionary json must be instances of: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.
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.
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];