How can I pass a "MutableArray with full of Objects" to another class by using NSUserDefaults? - iphone

How can I pass a "MutableArray with full of Objects" to another class by using NSUserDefaults? I know how to pass "MutableArray"s but this does not work!
So;
I have a MutableArray; 'myCityObjects', and I populate it with objects; 'cities'
In each 'cities' object there are properties like cityName, cityLocation etc...
[myCityObjects addObject:cities];
Now, what I want to do is to pass this MutableArray (filled with objects) to another class by using 'NSUserDefaults';
[[NSUserDefaults standardUserDefaults] setObject: myCityObjects forKey:#"MCO"];
And in the other class,
NSMutableArray *getMyCityObjects = [[NSArray alloc] init];
getMyCityObjects = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"MCO"];
But it doesn't work! I cannot get myCityObjects in the other class, "getMyCityObjects" is empty. How can I fix that?
Thanks,
E.

NSUserDefaults always returns immutable objects, even if the original object was mutable.
In your first View, You can save value in NSUserDefaults like this:
NSMutableArray *arr= [NSMutableArray arrayWithObjects:#"asd",#"dsa",nil];
[[NSUserDefaults standardUserDefaults] setObject:arr forKey:#"MCO"];
After this in another view, you can retrieve value from NSUserDefaults in this way.
NSMutableArray *abc = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"MCO"]];

Your array is nil because the objects in it (your custom objects) can't be serialised.
Please take a look at the NSCoding protocol. Objects you want to serialise (eg for writing to NSUserDefaults) must implement the methods -encodeWithCoder: and -initWithCoder.
I'm sure you'll find how this is rather easily done searching for the terms I gave you...

I have run into this problem before. The problem with the NSUserDefaults is that it can only contain strings, numbers, and booleans, and arrays or dictionaries of those types of values. My solution is to get around that by storing all the properties in NSDictionaries.
Create two class functions on your "cities" class (I'm calling it CityClass):
+(NSDictionary *)dictionaryFromCity:(CityClass *)myCity {
NSDictionary *returnDict = #{#"keyForIntProperty" : myCity.intProperty, #"keyForFloatProperty" : myCity.floatProperty, #"keyForNSStringProperty", myCity.NSStringProperty"};
return returnDict;
}
+(CityClass *)cityFromDictionary:(NSDictionary *)myDict {
CityClass *returnCity = [[CityClass alloc] init];
returnCity.intProperty = [[myDict objectForKey:#"keyForIntProperty"] intValue];
returnCity.floatProperty = [[myDict objectForKey:#"keyForFloatProperty"] floatValue];
returnCity.NSStringProperty = [myDict objectForKey:#"keyForNSStringProperty"];
//any other setup for the CityClass
return returnCity;
}
Now you can store and retrieve your objects without a problem using the new functions:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//store a CityClass object
NSDictionary *storageDict = [CityClass dictionaryFromCity:cityToStore];
[defaults setObject:storageDict forKey:#"keyForCity"];
//retrieve a CityClass object
NSDictionary *retrieveDict = [defaults objectForKey:#"keyForCity"];
CityClass *retrievedCity = [CityClass cityFromDictionary:retrieveDict];

What you can do here is create a Constructor in your other class for e.g.
-(void)initWithArrayOfObject:(NSMutableArray *)arr_OfObjects;
{
arr_SecondClassArrayOfObjects = [[NSMutableArray alloc]initWithArray:arr_OfObjects];
}
From your first class send this array as :
[objOfSecondClass initWithArrayOfObject: myCityObjects];

Related

NSUserDefaults NSObject with NSArray Object

I am trying to save object in NSUserDefaults, went throught many questions on this site but could not resolve the issue, my NSObject has an NSMutableArray of another object. like here the main object is HotelDC and it has an array "features" an array of FeactureDC objects.
Here is my code:
- (id)initWithCoder:(NSCoder *)decoder {
self = [[HotelDC alloc] init];
if (self != nil) {
self.hotel_id = [decoder decodeIntegerForKey:#"hotel_id"];
self.name = [decoder decodeObjectForKey:#"name"];
self.features = [decoder decodeObjectForKey:#"features"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeInt:hotel_id forKey:#"hotel_id"];
[encoder encodeObject:name forKey:#"name"];
[encoder encodeObject:features forKey:#"features"];//its a mutable array
}
how should I save it, and retrieve?? I am getting error as
Attempt to insert non-property value '<HotelDC: 0xa600fe0>' of class 'HotelDC'.
Note that dictionaries and arrays in property lists must also contain only property values.
Solution :
//Setting
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:hotelObjSelected];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:myEncodedObject forKey:#"selectHotelObject"];
[[NSUserDefaults standardUserDefaults] synchronize];
// retrieving
NSData *data = [defaults objectForKey:#"selectHotelObject"];
hotelObjSelected = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSUserDefaults is backed by a property list. Alas, proprety lists cannot contain serialised objects. Quoting from the manual:
A default object must be a property list, that is, an instance of (or
for collections a combination of instances of): NSData, NSString,
NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any
other type of object, you should typically archive it to create an
instance of NSData
You'll have to create your own serialised data file for saving the object directly, or serialise the objects as one of the allowed types. Annoyingly, NSUserDefaults doesn't call encodeWithCoder - it just screens the object type passed to setObject:forKey:. The best bet is to either serialise the fields of the HotelDC yourself, or archive the object to an NSData instance and store that.
I have did this by following way.check it. Below code is in for loop.
NSMutableArray *newEventArray = [[NSMutableArray alloc] init];
[newEventArray addObject:title];
[newEventArray addObject:alarmDate];
NSArray *iCalAlarmArray = [[NSUserDefaults standardUserDefaults] arrayForKey:#"alarmList"];
if(iCalAlarmArray == nil || [iCalAlarmArray count] <= 0)
{
iCalAlarmArray = [[NSMutableArray alloc] init];
}
iCalAlarmArray = [iCalAlarmArray arrayByAddingObject:newEventArray];
[[NSUserDefaults standardUserDefaults] setObject:iCalAlarmArray forKey:#"alarmList"];
[[NSUserDefaults standardUserDefaults] synchronize];
May this helps you.
you should write similiar encoding and decoding methods in FeatureDC and store it in an array and then encode here.
A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData

adding an item to at array in NSUserdefault

I am new to iOS development and could not find a way to solve this problem:
I have an app that has two views: one where the user enters some information (say a string), and another view where there is a tableview that includes all the strings that were ever entered (like a history view).
What I am trying to find is a good way to store the input string, then load it into the table view data source once the user switches to the history. I tried to use NSUserdefault but with not much success. Just getting messed up with the data structures, etc.
Here is what I am doing on the main view (where the user enters the input string):
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
arr1 = [defaults arrayForKey:#"historyNames"];
[arr1 addObject:string];
[defaults setObject:arr1 forKey:#"historyNames"];
From some reason I get a warning where I read to arr1, and honestly, I doubt that should work anyway.
Can anyone suggest how I could modify this to work properly and achieve what I am looking for?
Thanks.
[defaults arrayForKey:#"historyNames"];
Will return nil if you never initialized and saved an array for that key in NSUSerDefaults.
If you initialize and array and set it once (look up how to initialize default values for NSUserDefaults), it will return a proper array.
Then you can just do
NSMutableArray *arr1 = [NSMutableArray arrayWithArray:[[defaults arrayForKey#"historyNames"]];
Depending on how many elements this array will have, you may be better off using Core Data. Using user defaults is not very efficient for many/large values, just for small settings and things like that.
When your application starts up, look in user defaults to see if you have an array object already from the last time you used it. If there isn't one, call alloc and init for arr1. (You don't want to call it if you're accessing it from defaults.)
NSMutableArray * arr1;
arr1 = (NSMutableArray *) [defaults objectForKey:#"historyNames"];
if (!arr1) {
arr1 = [[NSMutableArray alloc] initWithCapacity:20];
}
In your main view, just add the input string, and save the defaults.
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject: arr1 forKey: #"historyNames"];
[prefs synchronize];

Pre-populating a NSUserDefaults array with Zero Value values

I need to pre-populate and save an array in NSUserDefaults so that downstream methods can read and write to ten values stored there. I've constructed this workable solution, but is there a better way of doing this?
Any insight is appreciated!
lq
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *myArray = [[NSMutableArray alloc] init];
// Set the array with ten Zero Value placeholders
for (NSUInteger i = 0; i < 10; ++i) {
[myArray addObject:[NSNumber numberWithInt:0]];
}
[userDefaults setObject:myArray forKey:#"someKeyName"];
[myArray release];
Later methods call this array like this:
- (void)doSomethingUseful {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *someUsefulArray = [[NSMutableArray alloc] initWithArray:[userDefaults objectForKey:#"someKeyName"]];
// read some values, write some values: int someInt = [someUsefulArray objectAtIndex:3]; // etc.
// store array values back to NSUserDefaults . . .
// IS THERE A WAY TO READ AND WRITE DIRECTLY TO INDEX 3 of the NSUserDefaults array instead???
[someUsefulArray release]
}
I've actually done the same thing in a shipping application. Sure, it doesn't feel elegant, but it does the job.
The only more elegant, and more convoluted, solution would be to use a data-driven approach:
Have a .plist file containing what you consider to be your default settings.
If the program detects that the user defaults is empty, it will load this default plist, and commit it to NSUserDefaults.
Using this method your code is not responsible for building the objects. However, if you are trying to accomplish a schema-upgrade, you're going to need to go back to the code.

NSUserDefaults won't save NSDictionary

I'm writing an application which uses NSUserDefaults as the data storage mechanism, and am hitting a problem when trying to save data (that conforms to the Property List protocols):
+ (BOOL)storeAlbum:(Album *)album
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *albums = (NSMutableDictionary *)[prefs objectForKey:#"my_adventure_book_albums"];
NSLog(#"Existing albums: %#",albums);
if (!albums)
albums = [NSMutableDictionary dictionaryWithObject:album forKey:#"album"];
else
[albums setObject:album forKey:#"album"];
NSLog(#"%#",album);
[prefs setObject:albums forKey:#"my_adventure_book_albums"];
return [prefs synchronize];
}
I get this output:
2010-06-29 17:17:09.929 MyAdventureBook[39892:207] Existing albums: (null)
2010-06-29 17:17:09.930 MyAdventureBook[39892:207] test
2010-06-29 17:17:09.931 MyAdventureBook[39892:207] *** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '{
album = test;
}' of class 'NSCFDictionary'.
The description method of Album looks like:
- (NSString *)description
{
// Convert to a NSDictionary for serializing
if (!title) title = #"";
if (!date) date = [NSDate dateWithTimeIntervalSinceNow:0];
if (!coverImage) coverImage = #"";
if (!images) images = [[NSArray alloc] initWithObjects:#"",nil];
//NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:title,date,coverImage,images,nil] forKeys:[NSArray arrayWithObjects:#"title",#"date",#"coverImage",#"images",nil]];
//NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:title,nil] forKeys:[NSArray arrayWithObjects:#"title",nil]];
//return [dict description];
return #"test";
}
All of the commented-out lines have the same result, so I just decided to see if the NSString "test" would work, which it (of course) doesn't.
But the object you put inside the dictionary, an Album* is most likely not a property list object, is it? Every object, all the way down, needs to be a property list object for this to work. A description method isn't good enough to make this happen.
As a workaround, you can use NSCoding and an NSKeyedArchiver to write out your dictionary to an NSData, which you can store among the preferences.
You can only put basic foundation types into a property list. NSUserDefaults writes preferences out as a property list. See here for property list allowed types. In a nutshell, it is numbers, strings, data, dates, and arrays and dictionaries of those. Dictionaries must have string keys.
NSUserDefaults always returns immutable objects, so you can't just cast them to mutable. Do [prefs objectForKey:#"my_adventure_book_albums"] mutableCopy] (and remember to release it when finished).

how can i store value in an NSArray using WritetoFile?

i wana store the index of seleted cell of table using NSArray, can u help me....
You can use user defaults or property list for this.
Example on user defaults. You have a controller class that has access to the index and will load it at startup and write it into plist whenever it's updated:
If you have some kind of controller class then you would put this code into + (void)initialize, it initialises the variable if it does not exists in plist:
+ (void)initialize
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults =
[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:5]
forKey:#"MyFunnyIndex"];
[defaults registerDefaults:appDefaults];
}
In your -(void)awakeFromNib (I'm assuming you're using some kind of controller class) load your last stored value:
-(void)awakeFromNib
{
int index =
[[NSUserDefaults standardUserDefaults] integerForKey:#"MyFunnyIndex"];
[somethingThatNeedsIndex setIndex:index];
// ...
}
Somewhere where the index is updated (or where you want to write it to plist), let's call it - (void)updateInterface:
- (void)updateInterface
{
[[NSUserDefaults standardUserDefaults]
setObject:[NSNumber numberWithInteger:index]
forKey:#"MyFunnyIndex"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I don't know if I understand the question correctly, but it sounds like you could use a property list to store this information. Property lists are very easy to use and quite efficient with small amounts of data.
Read the "Property List Programming Guide" for further explanation. There is even a tutorial in there.