Attempt to insert non-property value Objective C - ios

Hi l am trying to create a fourates lists from an restaurants Object, my application has a list of different restaurants, l want the ability for users to add favourate restaurants, and this code is not working
- (IBAction)toggleFav:(id)sender {
Restaurant *resto = [self restaure];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
[dic setObject:resto.price forKey:#"restoPrice"];
[dic setObject:resto.restaurantId forKey:#"restaurantId"];
[dic setObject:resto.restoAbout forKey:#"restoAbout"];
[dic setObject:resto.restoAddress forKey:#"restoAddress"];
[dic setObject:resto.restoBeverages forKey:#"restoBeverages"];
[dic setObject:resto.restoCategory forKey:#"restoCategory"];
[dic setObject:resto.restoEmail forKey:#"restoEmail"];
[dic setObject:resto.restoLogo forKey:#"restoLogo"];
[dic setObject:resto.restoName forKey:#"restoName"];
[dic setObject:resto.restoPhone forKey:#"restoPhone"];
[dic setObject:resto.restoCity forKey:#"restoCity"];
NSArray *dicArray = [dic allKeys];
if([sender isSelected]){
//...
[sender setSelected:NO];
NSMutableArray *array = [[[NSUserDefaults standardUserDefaults] objectForKey:#"restoName"] mutableCopy];
[array removeObject:dicArray];
[[NSUserDefaults standardUserDefaults] setObject:array forKey:#"restoName"];
} else {
//...
[sender setSelected:YES];
NSMutableArray *array = [[[NSUserDefaults standardUserDefaults] objectForKey:#"restoName"] mutableCopy];
[array addObject:dicArray];
[[NSUserDefaults standardUserDefaults] setObject:array forKey:#"restoName"];
[[NSUserDefaults standardUserDefaults] synchronize];
//NSLog(#"%#",[[NSUserDefaults standardUserDefaults] stringForKey:#"restoName"]);
}
}
' of class '__NSCFArray'. Note that dictionaries and arrays in property lists must also contain only property values.

If you don't want to bother about ensuring all your dictionary values are the property list types, then you can simply convert the dictionary into NSData,
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
[def setObject:[NSKeyedArchiver archivedDataWithRootObject:self.myDictionary] forKey:#"MyData"];
[def synchronize];
And to get back into a dictionary from sandbox:
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSData *data = [def objectForKey:#"MyData"];
NSDictionary *retrievedDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
self.myDictionary = [[NSDictionary alloc] initWithDictionary:retrievedDictionary];
Hope this helps someone. :D
ADDITIONAL NOTE: If you are getting a mutable dictionary, or mutable array, then remember to use "mutableCopy" method. Otherwise you can't add or delete objects from your retrieved dictionary/array. For example:
NSMutableDictionary *retrievedDictionary =
[[NSKeyedUnarchiver unarchiveObjectWithData:data] mutableCopy];
Or
NSMutableArray *retrievedArray =
[[NSKeyedUnarchiver unarchiveObjectWithData:data] mutableCopy];

You can only store property list types (array, data, string, number, date, dictionary) or urls in NSUserDefaults. You'll need to convert your model object to those.

Related

How to display data in NSMutableDictionary?

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"];

Adding new values to existing keys of nsuserdefault using nsmutablearray

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

Edit an object in an NSMutableArray saved with NSUserDefaults

i'm getting [__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object when I try to edit an object which I get from NSUserDefault.
I have searched through stackoverflow and tried making the mutable copy after retrieving the data but still getting the error. Here is the current code
I set this in the first view controller
NSMutableArray *settings=[[NSMutableArray alloc]init];
[settings addObject:[#{
#"single":#"Player1",
#"multiplesame":[[NSMutableArray alloc] initWithObjects:#"Player1",#"Player2",#"Player3",#"Player4",#"Player5", nil],
#"multipleDiff":[UIDevice currentDevice].name
}mutableCopy]];
[Reusables storeArrayToDefaults:SETTINGS_DETAILS objectToAdd:settings];
Now in another view controller, I'm trying to change the value of Player1 of single key to a name. For that this is how I retrieve the data.
NSMutableArray *setDetails = [[[NSUserDefaults standardUserDefaults] arrayForKey:SETTINGS_DETAILS] mutableCopy];
//setDetails= [[NSMutableArray alloc] initWithArray:[[NSUserDefaults standardUserDefaults] arrayForKey:SETTINGS_DETAILS]] ;
//setDetails = [setDetails mutableCopy];
NSLog(#"Details:%#",setDetails);
The log prints fine
Details:(
{
multipleDiff = "iPhone Simulator";
multiplesame = (
Player1,
Player2,
Player3,
Player4,
Player5
);
single = Player1;
}
)
But now when I try to change the value like this it gets crashed with the above error
[[setDetails objectAtIndex:0] setObject:#"Any Name" forKey:#"single"] ;
For reference this is how I save in NSUserDefaults
+(void)storeArrayToDefaults :(NSString *)keyName objectToAdd:(NSMutableArray *)arrayData
{
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults setObject:arrayData forKey:keyName];
[defaults synchronize];
}
Try this
NSMutableArray *setDetails = [NSMutableArray arrayWithArray:[[[NSUserDefaults standardUserDefaults] arrayForKey:SETTINGS_DETAILS] mutableCopy]];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[setDetails objectAtIndex:0]];
[dict setObject:#"Any Name" forKey:#"single"];
[setDetails replaceObjectAtIndex:0 withObject:dict];
Everything in NSUserDefaults is immutable. You create a mutable copy of the outer container but its contents are still immutable. So, to edit them, you need to take a mutable copy, update that and then reinsert (and re-add to defaults).
[[setDetails objectAtIndex:0] setObject:#"Any Name" forKey:#"single"];
changes to
NSMutableDictionary *dict = [[setDetails objectAtIndex:0] mutableCopy];
[dict setObject:#"Any Name" forKey:#"single"];
[setDetails replaceObjectAtIndex:0 withObject:dict];

NSUserDefaults returning (null)

I'm a newcomer to NSUserDefaults and am struggling to get my head around something I imagine is probably straightforward for most reading this.
I'm trying to retrieve a mutable array of strings if it exists in NSUserDefaults with the following code:
NSMutableArray *globalAppsArray;
if([[NSUserDefaults standardUserDefaults] objectForKey:#"globalAppsArray"] != nil)
{
NSLog(#"Array found. Contents: %#", globalAppsArray);
}
else
{
globalAppsArray = [[NSMutableArray alloc] initWithCapacity:0];
}
After adding any new data to it I then want to save it:
[[NSUserDefaults standardUserDefaults] setObject:globalAppsArray forKey:#"globalAppsArray"];
[[NSUserDefaults standardUserDefaults] synchronize];
When I relaunch the app, the mutable array is found OK but the contents are null.
Can someone tell me what I'm missing?
It should be something like this:
NSMutableArray *globalAppsArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"globalAppsArray"];
if(globalAppsArray != nil)
{
NSLog(#"Array found. Contents: %#", globalAppsArray);
}
else
{
globalAppsArray = [[NSMutableArray alloc] initWithCapacity:0];
}
check your code once,
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *globalAppsArray = [[defaults objectForKey:#"globalAppsArray"] mutableCopy];
if(globalAppsArray)
NSLog(#"Array found. Contents: %#", globalAppsArray);
else
globalAppsArray = [NSMutableArray array];

MutableDictionary turns immutable

In my first function i create an NSMutableDictionary and saves it in an array.
NSMutableArray* tempPlayersArray = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: #"kgpsTempArray"]];
NSMutableDictionary *tempPlayerDictArray = [[NSMutableDictionary alloc] init];
if (!(userDeviceName)) {
[tempPlayerDictArray setValue:userDeviceName forKey:#"DeviceName"];
}else{
[tempPlayerDictArray setValue:#"empty" forKey:#"DeviceName"];
}
[tempPlayersArray addObject:tempPlayerDictArray];
[defaults setObject:tempPlayersArray forKey:#"kgpsTempArray"];
[defaults synchronize];
In my second function i get it as NSCFDictionary - which is not mutable.
NSMutableArray* tempPlayersArray = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: #"kgpsTempArray"]];
NSMutableDictionary *dictionaryForSearching = [[NSMutableDictionary alloc] init];
NSLog(#"%#",[dictionaryForSearching class]);
dictionaryForSearching = [tempPlayersArray objectAtIndex:index];
NSLog(#"%#",[[tempPlayersArray objectAtIndex:index] class]);
NSLog(#"%#",[dictionaryForSearching class]);
The first log shows "NSDictionaryM".
The second log shows "NSCFDictionary".
And the third shows "NSCFDictionary" as well...
Can anyone explain me why? And how to fix it?
NSUserDefaults works with inmutable objects, so that's the reason that when you return your dictionary it's changed.
You can try this:
dictionaryForSearching = [[NSMutableDictionary alloc] initWithDictionary:[tempPlayersArray objectAtIndex:index]];
Yes, NSUserDefaults is free to copy, persist, and deserialize as it likes. Assume it does not return mutable objects. If you need a mutable object, make a mutable copy.
Every thing depends from here:
NSMutableArray* tempPlayersArray = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: #"kgpsTempArray"]];
Reading NSUserDefaults always give you Immutable object.

Resources