NSMutableArray is affecting the another NSMutableArray? - ios

I have two NSMutableArrays, both getting the same data. My problem is that when I assign the same data to both the mutable arrays from different dictionaries and perform operations on one NSMutableArray, it is affecting both arrays.
When I perform operations like replaceObjectAtIndex:WithObject:, the first time, the array is not affected but when the second replace is called both arrays have the replaced value. I think it is a reference issue.
Does anyone have a solution to this?
Name of the NSMutableArrays is helper.urlsRecording and helper.holdingArr.
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSMutableDictionary *dict2 = [[NSMutableDictionary alloc] init];
[dict setValue:outputFileURL forKey:#"URL"];
[dict setValue:#"1" forKey:#"index"];
[dict2 setValue:outputFileURL forKey:#"URL"];
[dict2 setValue:#"1" forKey:#"index"];
[helper.urlsRecording addObject:dict];
[helper.holdingArr addObject:dict2];
[helper.urlsRecording replaceObjectAtIndex:button.tag withObject:urlAr];//When this called second time, both the arrays is effected(helper.urlsRecording as well as helper.holdingArr).
How can I prevent the copying of the reference to another array?
Button Click:
if([button isSelected] == NO){
NSLog(#"Url Recording : %#",helper.urlsRecording);
[[helper.urlsRecording objectAtIndex:button.tag] removeObjectForKey:#"URL"];
button.selected = YES;
NSLog(#"Url Recording : %#",helper.urlsRecording);
}
else{
[helper.urlsRecording replaceObjectAtIndex:button.tag withObject:[helper.holdingArr objectAtIndex:button.tag]];
button.selected = NO;
NSLog(#"Url Recording : %#",helper.urlsRecording);
}
Note: NSMutableArray is defined globally in a class to access.

This is because your instance values are same for both dictionary.
So First create one mutableDictionary like below
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:outputFileURL forKey:#"URL"];
[dict setValue:#"1" forKey:#"index"];
And create second dictionary through mutableCopy, so instance will be different for both.
NSMutableDictionary *dict2 = [dict mutableCopy];
After that you can add them in to NSMutableArray and update accordingly.

Take a copy/mutableCopy dictionary & then add object to the MutableArray
[helper.urlsRecording addObject:[dict copy]];
[helper.holdingArr addObject:[dict2 copy]];

Related

Combining dictionaries: No class method for selector "addEntriesFromDictionary"

I am struggling with a dictionary in which I want to create a new dictionary from a series of keys (P, SP, and RP).
I have attempted to create a new NSMutableDictionary that combines individual Dictionaries that have have all the values for the P, SP, and RP keys respectively, but have gotten the error "No class method for selector "addEntriesFromDictionary" "
Here is my code:
NSMutableDictionary *newDict = [NSMutableDictionary addEntriesFromDictionary:self.allSPPositions];
and
#interface className ()
- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary;
#end
#implementation className
- (void)viewDidLoad {
Any help or insight would be appreciated! Thanks!
The compiler is telling you exactly what's wrong. You're trying to add items from a dictionary to the NSMutableDictionary class. You need to send the ad items from dictionary message to an instance of NSMutableDictionary.
This line:
NSMutableDictionary *newDict =
[NSMutableDictionary addEntriesFromDictionary:self.allSPPositions];
Should read
NSMutableDictionary *newDict =
[someDictionary addEntriesFromDictionary: self.allSPPositions];
(Where someDictionary is the dictionary to which you want to add items.)
or even
NSUInteger count = [self.allSPPositions count];
NSMutableDictionary *newDict =
[NSMutableDictionary dictonaryWithCapacity: count];
[newDict addEntriesFromDictionary: self.allSPPositions];
(Since your code appears to be trying to create a new, mutable dictionary and add the contents of self.allSPPositions.)
If your goal is to get a mutable copy of self.allSPPositions, there is a cleaner way to do that:
NSMutableDictionary *mutablePositions = [self.allSPPositions mutableCopy];
Uhh, here's an example that will compile and use the method in question, you should probably NOT call that method in your Interface since it's part of Apple's framework and is already predefined, unless you have a special reason for doing so:
NSMutableDictionary *dict =[[NSMutableDictionary alloc] init];
[dict setValue:#"Seattle" forKey:#"name"];
[dict setObject:[NSNumber numberWithInt:3] forKey:#"age"];
[dict setObject:[NSDate date] forKey:#"date"];
dict[#"city"]=#"Seattle";
[dict addEntriesFromDictionary:[NSMutableDictionary dictionaryWithObjectsAndKeys: #"Washington",#"location", nil]];
This is merely meant to get you started, but it shows you how to do this so that it works for you in your circumstances

Trying add NSMutableDictionary to NSMutableArray

I am very new to Objective-C and iOS programming so be gentle :)
I am trying to add an nsmutabledictionary to and nsmutablearray. I am succeeding but not with the results I was hoping for. Here is my code :
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
NSMutableDictionary *messages = [[NSMutableDictionary alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
[dictionary setValue:#"lat1" forKey:#"lat"];
[dictionary setValue:#"long1" forKey:#"long"];
[dictionary setValue:#"alt1" forKey:#"alt"];
[messages setObject:dictionary forKey:#"messages"];
[array addObject:messages];
[dictionary setValue:#"lat2" forKey:#"lat"];
[dictionary setValue:#"long2" forKey:#"long"];
[dictionary setValue:#"alt2" forKey:#"alt"];
[messages setObject:dictionary forKey:#"messages"];
[array addObject:messages];
NSLog(#"%#",array);
NSLog(#"%lu",(unsigned long)[array count]);
Here is the NSLog output:
2014-06-05 10:29:27.377 dicttest[4863:60b] (
{
messages = {
alt = alt2;
lat = lat2;
long = long2;
};
},
{
messages = {
alt = alt2;
lat = lat2;
long = long2;
};
}
)
2014-06-05 10:29:27.386 dicttest[4863:60b] 2
Here is what I was hoping to achieve:
2014-06-05 10:29:27.377 dicttest[4863:60b] (
{
messages = {
alt = alt1;
lat = lat1;
long = long1;
};
},
{
messages = {
alt = alt2;
lat = lat2;
long = long2;
};
}
)
2014-06-05 10:29:27.386 dicttest[4863:60b] 2
If I the dictionary straight to the array (instead of add the dictionary to messages and then adding that to the array) then I get the output I am looking for. Can somebody explain to me exactly what I am doing wrong?
It looks to me like you want:
An array
At index 0:
A dictionary with a single key "messages"
A dictionary with keys "alt", "lat", and "long"
At index 1:
A dictionary with a single key "messages"
A dictionary with keys "alt", "lat", and "long"
The data in the second array entry should use the same keys, but different data. As the others have pointed out, your mistake is using a single dictionary "dictionary"
When you add an object to a collection like a dictionary or array, the collection holds a pointer to the object, not a copy of the object. If you add the same object to a collection more than once, you have 2 pointers to the same object, not 2 unique objects.
When you add your "dictionary" object, to your structure, change it, and add it again, you are not getting the result you expect because both entries in your structure point to a single dictionary. When you change the values, it changes in both places.
The same goes for your "messages" dictionary. You need 2 of those as well.
Fix your code by adding new dictionaries, dictionary2 and messages2:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
NSMutableDictionary *dictionary2 = [[NSMutableDictionary alloc] init];
NSMutableDictionary *messages = [[NSMutableDictionary alloc] init];
NSMutableDictionary *messages2 = [[NSMutableDictionary alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
[dictionary setValue:#"lat1" forKey:#"lat"];
[dictionary setValue:#"long1" forKey:#"long"];
[dictionary setValue:#"alt1" forKey:#"alt"];
[messages setObject:dictionary forKey:#"messages"];
[array addObject:messages];
[dictionary2 setValue:#"lat2" forKey:#"lat"];
[dictionary2 setValue:#"long2" forKey:#"long"];
[dictionary2 setValue:#"alt2" forKey:#"alt"];
[messages2 setObject: dictionary2 forKey:#"messages"];
[array addObject: messages2];
NSLog(#"%#",array);
NSLog(#"%lu",(unsigned long)[array count]);
You might also look at using object literal syntax, e.g.:
dictionary[#"lat"] = #"lat1";
dictionary[#"long"] = #"long1";
dictionary[#"alt"] = #"alt1";
messages[#"messages"] = dictionary;
If you didn't need the whole thing to be mutable, you could even do everything with one line:
NSMutableArray *array = [
#[
#{#"messages": #{#"lat": #"lat1", #"long": #"long1", #"alt": #"alt1"}},
#{#"messages": #{#"lat": #"lat2", #"long": #"long2", #"alt": #"alt2"}}
];
Or to make it mutable:
NSMutableArray *array = [
#[
[#{#"messages":
[#{#"lat": #"lat1", #"long": #"long1", #"alt": #"alt1"} mutableCopy]} mutableCopy],
[#{#"messages":
[#{#"lat": #"lat2", #"long": #"long2", #"alt": #"alt2"} mutableCopy]} mutableCopy]
] mutableCopy];
EDIT: to add contents dynamically, you could use a method like this: (assuming that array is an instance variable)
- (void) addMessageWithLat: (NSString *) latString
long: (NSString *) longString
alt: (NSString *) altString;
{
NSMutableDictionary *messages = [[NSMutableDictionary alloc] init];
NSDictonary *contents =
[#{#"lat": latString,
#"long": longString,
#"alt": altString}
mutableCopy];
messages[#"messages"] = contents;
[array addObject: messages];
}
The problem is that you are making adding the new values in the same object reference. So the new Value will replace the older one. Just add this line before [dictionary setValue:#"lat2" forKey:#"lat"];
dictionary = [NSMutableDictionary alloc]init];
and this line before the second instance of [messages setObject:dictionary forKey:#"messages"];
messages = [[NSMutableDictionary alloc] init];

How to dynamically create a number of NSMutableArray(s)?

On touch up inside of SAVE button, the following code is executed:
- (IBAction)onSave:(id)sender {
savecount++;
[self saveNumberOfContacts];
NSMutableArray *myArray = [[NSMutableArray alloc] init];
[myArray addObject:nameTextField.text];
[myArray addObject:phoneTextField.text];
[myArray addObject:addressTextField.text];
[myArray addObject:cityTextField.text];
[myArray addObject:stateTextField.text];
[myArray addObject:zipcodeTextField.text];
[myArray writeToFile:[self saveFilePath] atomically:YES];
}
This creates a single array. I want to know how to dynamically create multiple arrays with the savecount variable suffixed at end of the array name.
For example, if my savecount is 3, then myArray1, myArray2, myArray3 should be created.
P.S. savecount changes its value dynamically.
EDIT: i dont want this method creating a number of arrays every time i call it. See, the user's info is stored in myArray1 when i click save for the first time. Now, the savecount gets increemented(say,savecount=2). When i enter another user's details and click save, i dont want myArray1 to be overwritten or disturbed; the second user's details must be independently saved in myArray2.
NSMutableArray *holder;
- (void)viewDidLoad
{
holder = [[NSMutableArray alloc] init];
}
- (IBAction)onSave:(id)sender {
savecount++;
[self saveNumberOfContacts];
NSMutableArray *myArray = [[NSMutableArray alloc] init];
[myArray addObject:nameTextField.text];
[myArray addObject:phoneTextField.text];
[myArray addObject:addressTextField.text];
[myArray addObject:cityTextField.text];
[myArray addObject:stateTextField.text];
[myArray addObject:zipcodeTextField.text];
[myArray writeToFile:[self saveFilePath] atomically:YES];
[holder addObject:myArray];
}
Have one global array in which you can hold dynamically created array. Now when you get value from holder, you will have separated myArray object.
If you are only using these arrays within one method, you could instead store the arrays in an array. This doesn't give you array names such as myArray1, myArray2, etc, but accomplishes the same overall task. Here's an example:
NSMutableArray *myArrays = [[NSMutableArray alloc] initWithCapacity:savecount];
for (NSUInteger i = 0; i < savecount; i++) {
NSMutableArray *newArray = [[NSMutableArray alloc] init];
[myArrays addObject:newArray];
[newArray addObject:nameTextField.text];
// continue adding your objects to newArray
}
Now you can reference your arrays as [myArrays objectAtIndex:0]...[myArrays objectAtIndex:savecount-1].
I think your problem is the path of save, or same path with appended array data.
If save data to different path:
- (NSString*)saveFilePath{
return [NSString stringWithFormat:#"%#/%#%d.%#", thePathToSave, fileName, savecount, fileType];
}
If save to same path with appended array data:
Replace:
[myArray writeToFile:[self saveFilePath] atomically:YES];
with
NSArray *fileData = [NSArray arrayWithContentsOfFile:[self saveFilePath]];
NSMutableArray *preDatas = nil;
if (preDatas.count == 0) {
preDatas = [NSMutableArray array];
}
else{
preDatas = [NSMutableArray arrayWithArray:fileData];
}
[preDatas addObject:myArray];
[preDatas writeToFile:[self saveFilePath] atomically:YES];

Adding NSMutableDictionary's in NSMutableArray

I'm scanning an NSMutableArray of dictionary's and request to a WebService a info from each data.
The problem is after get the data, i need to update 2 keys of the same array of dictionary's and when i added an object, the array continues empty.
What is wrong?!
PS: using ARC
NSMutableArray* arrayOfDicts = [NSMutableArray arrayWithObjects:
[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"2013",#"year",
#"a1beb511-7fe1-434b-ab87-a0d02fb47713",#"yearTB",
#"",#"receita_arrecadada",
#"",#"receita_prevista_atualizada",
nil],
[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"2012",#"year",
#"5d20f841-d790-4671-ae26-505c9a8c7f76",#"yearTB",
#"",#"receita_arrecadada",
#"",#"receita_prevista_atualizada",
nil],
nil];
__block NSMutableArray* arrayTemp = [[NSMutableArray alloc] init];;
__block NSMutableDictionary* dicTemp;
for(dicTemp in arrayOfDicts){
NSString* year = [dicTemp objectForKey:#"year"];
NSString* yearTB = [dicTemp objectForKey:#"yearTB"];
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
[RequestFacade getReceiptsTotalInYear:[NSString stringWithFormat:#"%#", yearTB] andCompletion:^(Receipt *receipt) {
//NSLog(#"%#",receipt.receita_arrecadada); // Print the correct actual value
[newDict addEntriesFromDictionary:dicTemp];
[newDict setObject:year forKey:#"year"];
[newDict setObject:yearTB forKey:#"yearTB"];
[newDict setObject:receipt.receita_arrecadada forKey:#"receita_arrecadada"];
[newDict setObject:receipt.receita_atualizada forKey:#"receita_atualizada"];
[arrayTemp addObject:newDict];
NSLog(#"%#", arrayTemp); // shows me the array of dicts
// until here, its ok!
}];
}
NSLog(#"%#", arrayTemp); // shows me an empty array...F*CK!
Initialise your arrayOfDict.
NSMutableArray * arrayOfDict = [[NSMutableArray alloc] init];
The array is empty because you are not initialising it. write this above line at the top and then add
[arrayOfDict arrayWithObjects: <UR ITEMS>];
Hope it works..!! Happy Coding

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