NSMutableArray unknown after initialization - ios

I am trying to initialize an NSMutableArray depending on if one exists in NSUserDefaults or not using and if/else statement.
if ([[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"] == nil) {
NSMutableArray *customers = [NSMutableArray arrayWithCapacity:10];
} else {
NSMutableArray *customers = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"]mutableCopy];
}
Customer *c = [[Customer alloc]init];
c.fName = self.fnameTextField.text;
c.lName = self.lnameTextField.text;
c.username = self.usernameTextField.text;
c.balance = [self.depositTextField.text floatValue];
[customers addObject:c];
[[NSUserDefaults standardUserDefaults] setObject:customers forKey:#"customers"];
[[NSUserDefaults standardUserDefaults] synchronize];
When trying to add an object to the array, I get "Unknown receiver 'customers.'" I'm not sure why I'm not able to use the array.

Try declaring the customers array outside your if statement
NSMutableArray *customers;
if ([[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"] == nil) {
customers = [NSMutableArray arrayWithCapacity:10];
} else {
customers = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"]mutableCopy];
}

I am quite sure you have written it like this,
NSMutableArray *customers;
if ([[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"] == nil) {
NSMutableArray *customers = [NSMutableArray arrayWithCapacity:10];
} else {
NSMutableArray *customers = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"]mutableCopy];
}
So, what is wrong here?
Note that if and else create their own scope, so the variable you declare inside if and else are new variable, not the one from outer scope. If you want to use customers from outer scope, do it like this,
NSMutableArray *customers;
if ([[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"] == nil) {
customers = [NSMutableArray arrayWithCapacity:10];
} else {
customers = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"customers"] mutableCopy];
}
Now, customers inside if and else block is the same variable that you have declared outside the if/else block.

Related

Crash interacting with NSUserDefaults and NSArray

I have an NSMutableArray in which I am adding objective and storing in user defaults, but while adding it is crashing.
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"]) {
bssidObserverArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"];
}
if (bssidObserverArray.count > 0) {
if (![bssidObserverArray containsObject:vendorID]) {
NSLog(#"bssidObserverArray %#",bssidObserverArray);
// In this line app is getting crashed
[bssidObserverArray addObject:vendorID];
[[NSUserDefaults standardUserDefaults] setObject:bssidObserverArray forKey:#"bssidObserverArray"];
}
}else{
[bssidObserverArray addObject:vendorID];
[[NSUserDefaults standardUserDefaults] setObject:bssidObserverArray forKey:#"bssidObserverArray"];
}
Any suggestions would be more helpful.
Assuming bssidObserverArray is NSMutable array then come the problem here .
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"]) {
bssidObserverArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"];
}
since NSUserdefaults returns immutable. you can do like this
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"]) {
NSArray *someArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"];
bssidObserverArray = [someArray mutableCopy];
}

NSUserDefaults can't update a nsmutable array

I saved a nsmutableArray inside a NSUserDefaults.
In the following case, it seems that all the elements from the array are equal to 0, even though in this case position 1 and position 5 should have 1 instead of 0 as a value. I know that NSUserDefaults elements are immutable but ...I did add that mutableCopy when retrieving the value.
Where am I wrong?
//create array
NSMutableArray *objArray = [[NSMutableArray alloc] init];
for (int i=0; i< 100;i++) [objArray addObject:#"0"];
[objArray replaceObjectAtIndex:1 withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
// update
elementPosition = 5;
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
//check the array
NSMutableArray *objArray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:nameFile]];
BOOL displayContent = true;
for (int i=0; i<[objArray count];i++)
{
if ([[objArray objectAtIndex:i] isEqualToString:#"0"])
{
displayContent = false;
}
}
I think when you retrieve and your mutable array from UserDefault and updated but you didn't set that new updated object to UserDefault, its having the old object which was set before. you have to store your update array again to userdefault with same key which update your UserDefautlt.
elementPosition = 5;
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
You should call the synchronize method
[[NSUserDefaults standardUserDefaults] synchronize];
I think you should fix your code follow my bellow code:
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
[[NSUserDefaults standardUserDefaults] synchronize];
...
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:nameFile];
[[NSUserDefaults standardUserDefaults] synchronize];
Replace your code with this:
//create array
NSMutableArray *objArray = [[NSMutableArray alloc] init];
for (int i=0; i< 100;i++){
[objArray addObject:#"0"];
}
[objArray replaceObjectAtIndex:1 withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
//First mistake. Missing this. Without this line the data is not saved in NSUserDefaults
[[NSUserDefaults standardUserDefaults] synchronize];
// update
elementPosition = 5;
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
//Second Mistake. You did not update the NSUserDefaults again.
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
[[NSUserDefaults standardUserDefaults] synchronize];
//check the array
NSMutableArray *objArray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]];
BOOL displayContent = true;
for (int i=0; i<[objArray count];i++)
{
if ([[objArray objectAtIndex:i] isEqualToString:#"0"])
{
displayContent = false;
}
//Third mistake. Once the BOOL is made false in an if block you have to make it true in the else block, otherwise the value of the BOOL will remain false even if it does not enter the if block.
else{
displayContent = true;
}
NsLog(#"ArrayIndex=[%d];DisplayContent=[%d]",i,displayContent);
}
Happy coding.

display data based on uiswitch state

I am trying to display data based on if the user has selected a switch. the user will have he ability to select either one or two switches to either both on or one or other on. Data will then be displayed according to the state of the switch.
I have managed to get this to load however its only displaying data from the dare array in the plist file and it dosnt matter which state the switch is in it displays dare not truth or both.
- (IBAction)shownext:(id)sender {
if (!self.plistArray) {
NSString *path = [[NSBundle mainBundle] pathForResource:
#"data" ofType:#"plist"];
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
if ([[defaults objectForKey:#"truthonoff"] isEqualToString:#"YES"] && [[defaults objectForKey:#"dareonoff"] isEqualToString:#"YES"] ) {
NSDictionary *plistDict1 = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray * plistArray1 = plistDict1[#"truth"];
NSDictionary *plistDict2 = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *plistArray2 = plistDict2[#"dare"];
self.plistArray = [[plistArray1 arrayByAddingObjectsFromArray:plistArray2] mutableCopy];
} else if ([[defaults objectForKey:#"truthonoff"] isEqualToString:#"YES"] ) {
NSDictionary *plistDict3 = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *plistArray3 = plistDict3[#"truth"] ;
self.plistArray = [plistArray3 mutableCopy];
NSLog(#"%#", plistArray);
} else ([[defaults objectForKey:#"dareonoff"] isEqualToString:#"YES"] ); {
NSDictionary *plistDict4 = [[NSDictionary alloc] initWithContentsOfFile:path];
NSMutableArray *plistArray4 = plistDict4[#"dare"];
self.plistArray = [plistArray4 mutableCopy];
NSLog(#"%#", plistArray);
}
}
}
-(void)stateSwitched:(id)sender {
UISwitch *tswitch = (UISwitch *)sender;
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
[defaults setObject: tswitch.isOn ? #"YES" : #"NO" forKey:#"truthonoff"];
[defaults synchronize];
}
-(void)stateSwitcheddare:(id)sender {
UISwitch *tswitch = (UISwitch *)sender;
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
[defaults setObject: tswitch.isOn ? #"YES" : #"NO" forKey:#"dareonoff"];
[defaults synchronize];
}
THis is my code for setting the object
Try to use boolForKey instead of objectForKey. And in the other hand, why does the else have a condition?:
if ([defaults boolForKey:#"truthonoff"] && [defaults boolForKey:#"dareonoff"]) {
// Both true
} else if ([defaults boolForKey:#"truthonoff"] && ![defaults boolForKey:#"dareonoff"]) {
// truthonoff true, dareonoff false
} else if (![defaults boolForKey:#"truthonoff"] && [defaults boolForKey:#"dareonoff"]) {
// truthonoff false, dareonoff true
} else {
// Both false
}
Make sure to do two things when you store boolean values in the NSUserStandardDefaults:
Use setBool setter: [[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"a_key"];
Remember to synchronize the standardUserDefaults to save the values.

Same object saved to NSUserDefaults over and over again when the NSMutableDictionary is different

It's driving me crazy, I did a log and I see the objects are different, but when I get then back from NSUserDefaults, all of the objects are the same.
My code:
- (void)breakTrapsToSave:(NSDictionary*)trapsDict firstTimeUpdate:(Boolean)firstTimeUpdate
{
// If traps already save
// we will get them from NSUserDefaults
// and then update them
if (!firstTimeUpdate)
{
allTraps = [self.sharedPrefs objectForKey:#"arrayOfAllTraps"];
}
// JSON Parsing
tempA = trapsDict[#"Envelope"];
tempB = tempA[#"Body"];
tempC = tempB[#"getTrapsResponse"];
tempD = tempC[#"getTrapsResult"];
tempE = tempD[#"TRAPS"];
self.lastUpdate = tempE[#"lastUpdate"];
[[NSUserDefaults standardUserDefaults] setObject:self.lastUpdate forKey:#"last_update"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Traps latest updated at: %#", self.lastUpdate);
tempF = tempE[#"TRAP"];
if (tempF.count <= 0)
{
newTrapsUpdates = false;
NSLog(#"NO NEW TRAPS!");
}
else
{
newTrapsUpdates = true;
NSLog(#"NEW TRAPS FOUND");
[tempF enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
tempA = tempF[idx];
NSString *finalResult;
NSString *key;
NSMutableDictionary *singleTrap = [[NSMutableDictionary alloc] init];
for (int i=0; i < node.count; i++)
{
finalResult = tempA[node[i]];
key = node[i];
if ([finalResult length] <= 0)
{
finalResult = #"0";
}
singleTrap[key] = finalResult;
}
if (allTraps.count <= 0)
{
allTraps = [[NSMutableArray alloc] initWithObjects:singleTrap, nil];
}
else
{
[allTraps addObject:singleTrap];
}
counter = idx;
}];
allTraps = [[IDANNetroads sharedInstance] removeDuplicatedFromArray:allTraps];
// Save all traps
[[NSUserDefaults standardUserDefaults] setObject:allTraps forKey:#"arrayOfAllTraps"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Total Traps: %d", allTraps.count);
NSLog(#"Total New Traps: %d", counter);
}
}
I did a log and I see allTraps[idx] = singleTrap; is different as it should be, but when I print the log for NSLog(#"allTraps: %#", allTraps); I see all of the objects are the last object.
EDIT:
Eventually, I replaced the singleTrap allocation and now it's inside the enumeration block:
NSMutableDictionary *singleTrap = [[NSMutableDictionary alloc] init];
And I added this code:
if (allTraps.count <= 0)
{
allTraps = [[NSMutableArray alloc] initWithObjects:singleTrap, nil];
}
else
{
[allTraps addObject:singleTrap];
}
So, the final code is edited.
Whatever singleTrap is, you're repeatedly mutating it and storing another reference to the same object in your allTraps array. You need to create (instantiate) a new item for each entry you want in your allTraps list.
It looks like singleTrap is an array of strings, so try:
allTraps[idx] = [singleTrap copy];

mutating method sent to immutable object

When I use this method first time it works fine, but when I called it second time I get the error "mutating method sent to immutable object". The problem is at line with "addObject" command.
-(IBAction) save: (id) sender{
NSMutableArray *placesT= [[NSUserDefaults standardUserDefaults] objectForKey:#"placesT"];
if (!placesT) {
placesT=[[[NSMutableArray alloc] init] autorelease];
}
[placesT addObject: [NSString stringWithFormat:#"%#", tagF.text] ];
NSUserDefaults *tUD=[NSUserDefaults standardUserDefaults];
[tUD setObject:placesT forKey:#"placesT"];
[tUD synchronize];
[self dismissModalViewControllerAnimated:YES];
}
As the documentation for NSUserDefaults says: "Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value." Whenever you want to change a collection you get from NSUserDefaults you have to get the immutable version, make a mutableCopy, modify that, and set it back again.
That is because the object stored in the NSUserDefaults is not the mutableArray but a normal array.
- (IBAction)save:(id)sender {
NSMutableArray *placesT = nil;
NSArray *tempArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"placesT"];
if (tempArray) {
placesT = [tempArray mutableCopy];
} else {
placesT = [[NSMutableArray alloc] init];
}
[placesT addObject:[NSString stringWithFormat:#"%#", tagF.text]];
NSUserDefaults *tUD = [NSUserDefaults standardUserDefaults];
[tUD setObject:placesT forKey:#"placesT"];
[tUD synchronize];
[self dismissModalViewControllerAnimated:YES];
[placesT release];
}
placesT is a non mutable array, either always set placesT a mutable object always or use following code.
NSMutableArray *placesT= [[[NSUserDefaults standardUserDefaults] objectForKey:#"placesT"] mutableCopy];
This should work:
-(IBAction) save: (id) sender {
NSMutableArray *placesT= [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults]
objectForKey:#"placesT"]];
if (!placesT) {
placesT=[[[NSMutableArray alloc] init] autorelease];
}
[placesT addObject: [NSString stringWithFormat:#"%#", tagF.text] ];
NSUserDefaults *tUD=[NSUserDefaults standardUserDefaults];
[tUD setObject:placesT forKey:#"placesT"];
[tUD synchronize];
[self dismissModalViewControllerAnimated:YES]; }

Resources