NSMutableDictionary, alloc, init and reiniting - cocoa-touch

In the following code:
//anArray is a Array of Dictionary with 5 objs.
//here we init with the first
NSMutableDictionary *anMutableDict = [[NSMutableDictionary alloc] initWithDictionary:[anArray objectAtIndex:0]];
... use of anMutableDict ...
//then want to clear the MutableDict and assign the other dicts that was in the array of dicts
for (int i=1;i<5;i++) {
[anMutableDict removeAllObjects];
[anMutableDict initWithDictionary:[anArray objectAtIndex:i]];
}
Why this crash? How is the right way to clear an nsmutabledict and the assign a new dict?
Thanks guy's.
Marcos.

You do not "reinit" objects — ever. Initialization is meant to be used on a newly alloced instance and might make assumptions that aren't true after initialization is complete. In the case of NSMutableDictionary, you can use setDictionary: to completely replace the contents of the dictionary with a new dictionary or addEntriesFromDictionary: to add the entries from another dictionary (without getting rid of the current entries unless there are conflicts).
More generally, you could just release that dictionary and make a mutableCopy of the dictionary in the array.

If you use an autoreleased dictionary, your code will be a lot simpler:
NSMutableDictionary *anMutableDict = [NSMutableDictionary dictionaryWithDictionary:[anArray objectAtIndex:0]];
... use of anMutableDict ...
for (int i=1; i<5; i++)
{
anMutableDict = [NSMutableDictionary dictionaryWithDictionary:[anArray objectAtIndex:i]];
}
But I don't see the point of that loop you have at the end there.

This isn't how you use init/alloc. Instead, try:
//anArray is a Array of Dictionary with 5 objs.
//here we init with the first
NSMutableDictionary *anMutableDict = [[NSMutableDictionary alloc] initWithDictionary:[anArray objectAtIndex:0]];
... use of anMutableDict ...
//then want to clear the MutableDict and assign the other dicts that was in the array of dicts
for (int i=1;i<5;i++) {
[anMutableDict removeAllObjects];
[anMutableDict addEntriesFromDictionary:[anArray objectAtIndex:i]];
}

Related

Objective C. NSMutable Dictionary adding value to existing key

Is there any way to add a value to an existing key on a NSMutableDictionary?
Here is snippet of my code
NSMutableArray *mainFeedList = [NSMutableArray array];
[mainFeedList addObjectsFromArray:feedList];
for(int i = 0; i < mainFeedList.count; i++){
NSMutableArray *allFeed = [NSMutableArray array];
NSString *categoryId = [mainFeedList[i] valueForKey: #"categoryId"];
[allFeed addObject:mainFeedList[i]];
if(allFeed != nil && allFeed.count > 0) {
[feedContent setObject:allFeed
forKey:[combinedCategories[(int)[categoryId integerValue]] valueForKey: #"name"]];
}
Sample scenario:
NSMutableDictionary *mDict = #{#"key1":#"value1",#"key2": #"value2"};
I know that
[mDict setObject:mArray forKey:#"key1"];
will set an object to key1 but what I need is
add another object to key1 without replacing existing object (i need it both)
A structure of any NSDictionary is "one key to one object". If you would like to build a structure which maps one key multiple objects, you need an NSDictionary that maps keys to collections, such as NSArray or NSMutableArray:
NSMutableDictionary *mDict = #{
#"key1": [#[ #"value1" ] mutableCopy]
, #"key2": [#[ #"value2" ] mutableCopy]
};
Now you can add values to keys without replacing the existing ones:
[mDict[#"key1"] addObject:#"value3"];
NSDictionary only allows a single object corresponding to a single key. If you would like to add multiple objects corresponding to a single key, if you have string type of object then you can use separators also to combine strings like:
[mDict setObject:[NSString stringWithFormat:#"%#,%#", [mDict objectforKey:#"key1"], #"value2"] forKey:#"key1"];
Otherwise, you have to take collections, which you have already defined in your question.
add another object to key1 without replacing existing object...
why not set an dict to key1?
before:
[dict setObject:#"a" forKey:#"key1"];
U wanna:
add #"b" to "key1", in dict;
why not like:
[dict setObject:#{#"a":#"subKey1", #"b":#"subKey2"} forKey:#"key1"];
I would suggest storing an array as a key in your dictionary like I do below :
// Setting the value for "key1" to an array holding your first value
NSMutableDictionary *mDict = #{#"key1":#["value1"],#"key2": #"value2"};
Now when I want to add a new value I would do this:
// Create temp array
NSMutableArray *temp = mDict[#"key1"];
// Add new object
[temp addObject:#"value3"];
// Convert temp NSMutableArray to an NSArray so you can store it in your dict
NSArray *newArray = [[NSArray alloc] initWithArray:temp];
// Replace old array stored in dict with new array
mDict[#"key1"] = newArray;
Furthermore, if you are not sure if an array is already stored for that key you can run a check and populate with an empty dictionary like below:
if (mDict[#"key1"] == nil) {
mDict[#"key1"] = #[];
}

How to remove at most one object from nsmutablearray?

I want to insert a bunch of objects into a NSMutableArray. Then I would remove them one by one when the time fits. Every inserted objects must be removed.
However, if I have several copies of the same object, I just want to remove one of them.
How would I do that?
NSMutableArray *arr = [#[#1, #1, #5, #6, #5] mutableCopy]; // a copy of your array
NSMutableSet *removedObjects = [NSMutableSet setWithArray:arr];
for (id obj in removedObjects) {
[arr removeObjectAtIndex:[arr indexOfObject:obj]]; // removes the first identical object
}
Also note that if your array is filled with custom objects, you need to implements hash and isEqual: so the comparisons can work.
are any of these functions what you are looking for?
[array removeObjectAtIndex:(NSUInteger)];
[array removeLastObject];
[array removeObject:(id)];
[myMutableArray removeObjectAtIndex: 0];
or
[myMutableArray removeLastObject];
To remove the first and last objects respectively.
I don't think it's a good design for [NSMutableArray removeObject:] to remove all the occurences but we can avoid it by first getting an index using indexOfObject: and then removing the object using removeObjectAtIndex:
i prefer using index of object; it will return the index of object first appeared in the array
NSMutableArray * first = [#[#"2",#"3",#"4",#"5"] mutableCopy];//your first array
NSMutableArray * willBeAppend = [#[#"2",#"3",#"4",#"5"] mutableCopy];//new objects to append
[first addObjectsFromArray:willBeAppend];//append new objects
id objectToBeRemoved = #"3";// object will be removed
NSInteger objIx = [first indexOfObject:objectToBeRemoved];// index of object
if (objIx != NSNotFound) {
[first removeObjectAtIndex:objIx]; //remove object
NSLog(#"%#",first);
}

Load an element value of an array to another array Xcode Objective-C

Here I am getting the cityName1 with the city names like Piscataway, Iselin, Broklyn etc fetched from the tgpList1 array and I need to put the values into an array called item5.
There are 133 records fetched by the above iteration. The following code stores only the last record's cityName1 and not the entire list of city names though inside the loop.
I tried many ways but I am missing something.
tgpList1 is an array.
tgpDAO is an NSObject with two objects NSString *airportCode and NSString *cityName
NSArray *item5 = [[NSArray alloc]init];
for (int currentIndex=0; currentIndex<[tgpList1 count]; currentIndex++)
{
tgpDAO *tgpTable = (tgpDAO *)[self.tgpList1 objectAtIndex:currentIndex];
NSLog(#"The array values are %#",tgpList1);
NSString *cityName1 = tgpTable.cityName;
item5 =[NSArray arrayWithObjects:cityName1, nil];
}
Use mutable array.
{
NSMutableArray *item5 = [[NSMutableArray alloc]initWithArray:nil];
for (int currentIndex=0; currentIndex<[tgpList1 count]; currentIndex++) {
tgpDAO *tgpTable = (tgpDAO *)[self.tgpList1 objectAtIndex:currentIndex];
NSLog(#"The array values are %#",tgpList1);
NSString *cityName1 = tgpTable.cityName;
[item5 addObject:cityName1];
}
}
Instead of
item5 =[NSArray arrayWithObjects:cityName1, nil];
use
[item5 addObject:cityName1];
There are more ways of achieving that. However, this is the one that is designed for that purpose and the most "readable" from my pont of view.
If you need to clear the contents of item5 before then call
[item5 removeAllObjects];
right before the for loop.
What you were doing: arrayWithObjects allways creates a new array that ist made of the objects that are passed to it as aguments. If you do not use ARC, then you would create some serious memory leak with your code because arrayWithObjects creates and retains an object on every loop and on the next loop all references to the array object, that was just created, are lost without being released. If you do ARC then you do not have to worry about in this case.
NSMutableArray *myCities = [NSMutableArray arrayWithCapacity:2]; // will grow if needed.
for( some loop conditions )
{
NSString* someCity = getCity();
[myCities addObject:someCity];
}
NSLog(#"number of cities in array: %#",[myCities count]);

objective-c changing array contents inside for loop

I have an issue that (I think) might have to do with scope, but I'm not sure. I'm trying to do something that I think should be simple, but I am getting a strange result, and I could truly use some advice. I would say I'm an early-objective-c programmer, but not a complete newb.
I have written a function in objective-c that I would like to use to change the key-names in a mutable array of mutable dictionary objects. So, I want to pass in a mutable array of mutable dictionary objects, and return the same mutable array with the same dictionary objects, but with some of the key-names changed. Make sense?
I have tried several log statements in this code, which seem to indicate that everything I'm doing is working, except when the for loop is finished executing (when I try to test the values in the temp array), the array appears to contain only the LAST element in the source array, repeated [source count] times. Normally, this would lead me to believe I'm not writing the new values correctly, or not reading them correctly, or even that my NSLog statements aren't showing me what I think they are. But might this be because of scope? Does the array not retain its changes outside of the for loop?
I have put a fair amount of time into this function, and I have exhausted my bag of tricks. Can anyone help out?
-(NSMutableArray *)renameKeysIn:(NSMutableArray*)source {
/*
// Pre:
// The source array is an array of dictionary items.
// This method renames some of the keys in the dictionary elements, to make sorting easier later.
// - "source" is input, method returns a mutable array
*/
// copy of the source array
NSMutableArray *temp = [source mutableCopy];
// a temporary dictionary object:
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
// These arrays are the old field names and the new names
NSMutableArray *originalField = [NSMutableArray arrayWithObjects:#"text", #"created_at",nil];
NSMutableArray *replacedField = [NSMutableArray arrayWithObjects:#"title", #"pubDate", nil];
// loop through the whole array
for (int x =0; x<[temp count]; x++) {
// set the temp dictionary to current element
[dict setDictionary:[temp objectAtIndex:x]];
// loop through the number of keys (fields) we want to replace (created_at, text)... defined in the "originalField" array
for (int i=0; i<[originalField count]; i++)
{
// look through the NSDictionary item (fields in the key list)
// if a key name in the dictionary matches one of the ones to be replaced, then replace it with the new one
if ([dict objectForKey:[originalField objectAtIndex:i]] != nil) {
// add a new key/val pair: the new key *name*, and the old key *value*
[dict setObject:[dict objectForKey:[originalField objectAtIndex:i]]
forKey:[replacedField objectAtIndex:i]];
// remove the old key/value pair
[dict removeObjectForKey:[originalField objectAtIndex:i]];
}// end if dictionary item not null
}// end loop through keys (created_at, text)
[temp replaceObjectAtIndex:x withObject:dict];
}// end loop through array
// check array contents
for (int a=0; a<[temp count]; a++){
NSLog(#"Temp contents: ############ %#",[[temp objectAtIndex:a] objectForKey:#"pubDate"]);
}
return temp;
} // end METHOD
I think the issue is on the line with:
[dict setDictionary:[temp objectAtIndex:x]];
Since these things are almost all working in pointers (instead of copying contents), every element of your temp array will point to the dict dictionary, which is set to be whatever the latest key's dictionary is. I think setting the actual pointer will fix the issue.
dict = [temp objectAtIndex:x];

How to create a 2D NSArray or NSMutableArray in objective C?

I want to ask about the objective C question. I want to create a 2D NSArray or NSMutableArray in objective C. What should I do? The object stored in the array is NSString *. Thank you very mcuh.
This is certainly possible, but i think it's worthy to note that NSArrays can only hold objects, not primitive types.
The way to get around this is to use the primitive wrapper type NSNumber.
NSMutableArray *outer = [[NSMutableArray alloc] init];
NSMutableArray *inner = [[NSMutableArray alloc] init];
[inner addObject:[NSNumber numberWithInt:someInt]];
[outer addObject:inner];
[inner release];
//do something with outer here...
//clean up
[outer release];
Try NSMutableDictionary with NSNumbers as keys and arrays as objects. One dimension will be the keys, the other one will be the objects.
To create the specific "2D array"
NSMutableDictionary *twoDArray = [NSMutableDictionary dictionary];
for (int i = 0; i < 10; i++){
[twoDArray setObject:arrayOfStrings forKey:[NSNumber numberWithInt:i]];
}
To pull the data
NSString *string = [[twoDArray objectForKey:[NSNumber numberWithInt:3]] objectAtIndex:5];
//will pull string from row 3 column 5 -> as an example
Edited to make my answer more applicable to the question. Initially I didn't notice that you were looking for a 2D array. If you know how many by how many you need up front you can interleave the data and have a stride. I know that there are probably other (more objective standard) ways of having arrays inside of an array but to me that gets confusing. An array inside of an array is not a 2 dimensional array. It's just a second dimension in ONE of the objects. You'd have to add an array to each object, and that's not what I think of as a 2 dimensional array. Right or wrong I usually do things in a way that makes sense to me.
So lets say you need a 6x6 array:
int arrayStride=6;
int arrayDepth=6;
NSMutableArray *newArray = [[NSMutableArray alloc] initWithCapacity:arrayStride*arrayDepth];
I prefer to initialize the array by filling it up with objects;
for(int i=0; i<arrayStride*arrayDepth; i++) [newArray addObject #"whatever"];
Then after that you can access objects by firstDim + secondDim*6
int firstDim = 4;
int secondDim = 2;
NSString *nextString = [newArray objectAtIndex:firstDim+secondDim*6];