Add objects to NSMutableArray that don't reference each other - ios

First question:
Basically I'm attempting to add NSMutableDictionary objects to an NSMutableArray by using a method addItem.
-(void)addItem:(id)ObID name:(id)ObName description:(id)ObDesc menuName:(id)ObmName menuID:(id)ObmID mid:(id)Obmid pod:(id)pod type:(id)obType price:(id)price
{
NSMutableDictionary *itemToAdd = [[NSMutableDictionary alloc]init];
[itemToAdd setValue:ObID forKey:#"id"];
[itemToAdd setValue:ObName forKey:#"name"];
[itemToAdd setValue:ObDesc forKey:#"description"];
[itemToAdd setValue:ObmName forKey:#"mname"];
[itemToAdd setValue:ObmID forKey:#"menu_id"];
[itemToAdd setValue:Obmid forKey:#"mid"];
[itemToAdd setValue:pod forKey:#"POD"];
[itemToAdd setValue:obType forKey:#"Type"];
[itemToAdd setValue:price forKey:#"Price"];
[itemToAdd setValue:#"1" forKey:#"Amount"];
[items addObject:itemToAdd];
}
However when this method is called again later the next object that is added to the overwrites the value of an object with the same keys. Im aware this is because an array simply retains a memory address, hence when the same object simply with a different type "obType" is added all of those values change.
How am I able to add objects to an NSMutableArray without them referencing each other?
Example:
Output after adding one object:
{
Amount = 1;
POD = BOTH;
Type = {
0 = Vegetarian;
1 = Aussie;
};
description = "Online Special Only - Two Large Pizza's $25 (No half halves or extra toppings!) Enjoy!";
id = 7596;
"menu_id" = 112;
mid = 112;
mname = "Deal";
name = "Hungry? Two Large Pizzas!";
}
)
Output after adding another object of same ID however of a different type:
{
Amount = 1;
POD = BOTH;
Type = {
0 = "Plain";
1 = Aussie;
};
description = "Online Special Only - Two Large Pizza's $25 (No half halves or extra toppings!) Enjoy!";
id = 7596;
"menu_id" = 112;
mid = 112;
mname = "Deal";
name = "Two Large Pizzas!";
},
{
Amount = 1;
POD = BOTH;
Type = {
0 = "Plain";
1 = Aussie;
};
description = "Online Special Only - Two Large Pizza's $25 (No half halves or extra toppings!) Enjoy!";
id = 7555;
"menu_id" = 112;
mid = 112;
mname = "Deal";
name = Two Large Pizzas!";
}
)
As can be seen both object types have changed.
Ok so I solved the problem, not 100% sure why.
I was passing in the type object as an NSMutableDictionary which if an item had 2 variations, one object in the dictionary would have a key of 0 the other 1 when passed in like this they overwrite each other.
Passing just the values in as an NSArray fixes this.
Done by passing in:
NSArray * values = [selectedItemOptions allValues];
Thanks all who helped.

I can't give you the answer, there is not enough information provided to do that, but maybe I can help you figure it out yourself. You write:
Im aware this is because an array simply retains a memory address, hence when the same object simply with a different type "obType" is added all of those values change.
That is not what happens in your code, though there are situations where what is in an array may appear to change - and that is what you are probably seeing. The line:
NSMutableDictionary *itemToAdd = [[NSMutableDictionary alloc]init];
generates a new, never before seen, mutable dictionary. You can log the address (effectively the identity(1)) of this object by adding:
NSLog(#"Created itemToAdd: %p", itemToAdd);
after the above line. The %p format will produce the address of the newly created object, and every object has a unique address. When you then get to the line:
[items addObject:itemToAdd];
The new dictionary is added to whichever array is referenced by items - and that is very important. Any variable, such as items and itemToAdd, references an object, it is not the object itself. So the array being referenced by items could change between calls to addItem:. You should check this and you can do that by adding(2):
NSLog(#"addItem called, items = %p containing %ld element", items, items.count);
for(id someThing in items)
NSLog(#" element: %p", someThing);
to the start of your method. This will first tell you the address of the array currently referenced by items and how many items that array contains. The for loop will then output the address of each element of the array (if there are any).
Further note that addObject: will always add an item to the array, it doesn't matter if the same item is already in the array - add it twice and the array appears to have two elements, both of which reference the same item. When the above code displays the count it should be increasing unless you are removing elements from the array somewhere.
Add those statements and look at the results. Among the possibilities that would produce the results you are reporting:
The array referenced by items is changing
The dictionary you add is being removed
Etc.
HTH
(1) Addresses can be reused, after an object is no longer required and destroyed by ARC its memory may be reused for a new object. So the address does not strictly identify a unique object, you just need to be aware of this
(2) I am assuming 64-bit here, if not you need to change the %ld format or add a cast.

Related

How can I implement my logic properly to populate my UITableView

Sorry guys, this problem I am running into is pretty trivial. I just can't wrap my head around it so hope someone can help me. Your help is really appreciated. I am getting JSON data through NSURLConnectDelegate with a web API. I get something like this back:
(
{
id = 340
name = Vicent },
{
id = 339
name = Johny },
{
id = 338
name = Eric }
)
and I save it in a NSMutableArray as a global variable. Now, I have a NSSet of "ids". For example:
{
340, 339
}
In the numberOfRowsInSection, I return the set's count. I am trying to load only the ids in the NSSet from the array with the data saved from the webAPI, so I do something like this in cellForRowIndexPath:
for (NSNumber *num in [set allObjects]) {
NSString *newString = [[savedArray objectAtIndex:indexPath.row]
NSString *new = [num stringValue];
if ([new isEqual:newString]) {
}}
How can I just populate the ids I want?
The JSON makes it look like you have an array of dictionaries, which is a reasonable data structure to use as the data source for a table view.
It sounds like you're trying to filter your array to only include the items that are in your set. Is that right?
If so, you could write code that would create a new array containing the subset of your array elements who's ID is also in your set. There are at least a half-dozen ways to do that. One fairly simple approach would be to use the NSArray method indexesOfObjectsPassingTest. You'd pass that method a block of code that would check each array element to see if it's id object was in your set.
That would give you an NSIndexSet with the indexes of the items in your array who's ID are in your set. Then you could use the NSArray method objectsAtIndexes to get an array of only the objects that are also in the set. Something like this (Assuming that your array of dictionaries is called savedArray and your set is called allObjects:
//get the indexes of items in the array savedArray who's id appears in the set allObjects
NSIndexSet *indexes = [savedArray indexesOfObjectsPassingTest:
^(NSDictionary *obj,
NSUInteger idx,
BOOL *stop)
{
return [allObjects member: obj[#"id"]] != nil;
}
];
//Now build an (immutable) array of just the objects who's ID are in the set
NSArray *subArray = [savedArray objectsAtIndexes: indexes];
The array subArray created above is immutable. If you need a mutable array you would need to make a mutable copy, which is a one-line change.
Disclaimer: I still struggle a little with block syntax, so the above might not be exactly correct, but it gives you the general idea.

How to avoid NSMutable array add object values changes before adding object to NSMutable array?

I am new to Objective C. I had used following code.
for (int i = 0; i < [ValueisFound count]; i++)
{
NSString* ObjectName = [NSString stringWithUTF8String:name];
ObjectName = [[NSClassFromString([NSString stringWithUTF8String:samType]) alloc]init];
NSMutableDictionary* jsonDictionary=[TemplateClass SeparateArray:jsonValue_1 key:[arrayofKeys objectAtIndex:j] index:i];
ObjectName = [TemplateClass JsonPharser:str1 jsonObject:jsonDictionary];
NSMutableArray *samArray=[[NSMutableArray alloc]initWithObjects:[TemplateClass JsonPharser:str1 jsonObject:jsonDictionary], nil];
[manoj_Array addObject:samArray];
[samArray release];
[ObjectName release];
}
While executing for loop:
at i=0, Object has value(number=10), now manoj_Array also has (number=10).
at i=1, Object has value(number=12), now manoj_Array has (number=12,number=12).
But i want the result as manoj_Array has (number=10,number=12). I don't know how that array values are changing to last value.
My mind
samArray and manoj_Array is shared the memory Reference Thats why last value is insert to the manoj_Array
i = 0 value is Store by the address of 1000
i = 1 value is Store by the address of 1002
but manoj_Array share the memory so change the Last value is Added to manoj_Array
You can implement KVO in order to know when a value has changed and handle its behaviour.

Find object by name in NSMutableArray

I have a generic person object with properties personName, lastName, and age. I am storing the user input into an NSMutableArray and I wanted to find a under by his/her name in the array. I have tried finding a bunch of different solutions but none that quite really work.
This is my main.m
#autoreleasepool {
char answer;
char locatePerson[40];
//Create mutable array to add users for retrieval later
NSMutableArray *people = [[NSMutableArray alloc] init];
do{
Person *newPerson = [[Person alloc]init];
[newPerson enterInfo];
[newPerson printInfo];
[people addObject:newPerson];
NSLog(#"Would you like to enter another name?");
scanf("\n%c", &answer);
}while (answer == 'y');
NSLog(#"Are you looking for a specific person?");
scanf("%c", locatePerson);
//This is where I need help
int idx = [people indexOfObject:]
}
This is very basic but I am new to objective-c and I wanted to try and find the user by name. The solutions I've seen have used the indexesOfObjectsPassingTest method. But I was wondering if I can't just use the indexOfObjectmethod the way I did there to locate a person by its name?
Any help is appreciated.
This is one of those hard problems you should avoid with some up-front design. If you know that you are putting things into a collection class and will need to get them out again based on some attribute (rather than by order of insertion) a dictionary is the most efficient collection class.
You can use a NSDictionary keyed with Person's name attribute. You can still iterate over all the objects but you will avoid having to search the whole collection. It can take a surprisingly long time to find a matching attribute in a NSArray! You wouldn't even have to change your Person object, just do
NSDictionary *peopleDictionary = #{ person1.name : person1, person2.name : person2 };
or add them one by one as they are created into a NSMutableArray.
You can try something like this assuming that 'name' is a property for your Person class.
NSUInteger i = 0;
for(Person *person in people) {
if([person.name isEqualToString:locatePerson]) {
break;
}
i++;
}

IOS Objective C - Updating NSArray values from another NSArray

I have a NSArray with objects Called Houses, each object has 3 fields = id,address,price
I can set the value by using
[house setValue:#"£100k" forKey:#"price"];
However I have another NSArray called Movements, each object has 2 fields, id & price
so how do I update the 1st array with details from the 2nd array.. in english it I trying to do "Update house price with movement price where house id = movement id"
Thanks in advance
Sounds like you want a double loop:
for (House* house in houses)
for (Movement* movement in movements)
{
if (house.id == movement.id)
house.price = movement.price
}
If there will only be one such instance you may want to break early, you'll need an extra BOOL for this:
BOOL breaking = false;
for (House* house in houses)
{
for (Movement* movement in movements)
{
if (house.id == movement.id)
{
house.price = movement.price
breaking = true;
break;
}
}
if (breaking) break;
}
Edit: If you are doing this kind of thing frequently, you probably want to construct a dictionary keyed on the id field so you can look up an object quickly rather than by looping the whole array. NSDictionary is the class you want for this, also note that keys must be objects, so if your id field is an int you'll want to convert it to an NSNumber with [NSNumber numberWithInt:] before using it as a key.

NSMutableArray or NSMutableDictionary : which is best for this scenario?

I need to scroll through several thousands of words to categorize them... to determine which words have the same pattern. (this part works)
For example, a four letter word that has two m's in 2nd & 4th position represent a pattern ("-m-m"). Once I have gone through all the words, I will know how many words there are for any given pattern. I am scrolling through now, but the problem I have is 'remembering' how many words I have in any given pattern.
I was thinking of using NSMutableDictionary and have the key be the pattern ('-m-m-') and the object represent the count of that pattern. This means every time I come across a pattern, I look up that pattern in the dictionary, get the key, increment the key, and put it back in the dictionary.
I need help with both the decision and syntax for performing this task.
Thank You
The answer to your question was this part of your (given) question "I will know how many words there are for any given pattern.". I would use an array of dictionary. You use the dictionary to store key value pair: a known pattern and the count. And you use the array to store those KVP records. So the next time you detect a pattern, search for the array for that record (dictionary), if found, increment the count. If not, create new record and set the count to 1.
Added sample code:
#define kPattern #"Pattern"
#define kPatternCount #"PatternCount"
-(NSMutableDictionary *)createANewDictionaryRecord:(NSString *) newPattern
{
int count = 1;
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
newPattern, kPattern,
[NSString stringWithFormat:#"%i",count], kPatternCount,
nil];
return myDictionary;
}
-(void)addANewPatternToArray:(NSMutableDictionary *)newDictionary
{
// NSMutableArray *myArrayOfDictionary = [[NSMutableArray alloc]init]; // you need to define it somewhere else and use property etc.
[self.myArrayOfDictionary addObject:newDictionary]; //or [self.myArrayOfDictionary addObject:newDictionary]; if you follow the recommendation above.
}
-(BOOL)existingPatternLookup:(NSString *)pattern
{
for (NSMutableDictionary *obj in self.myArrayOfDictionary)
{
if ([[obj objectForKey:kPattern] isEqual:pattern])
{
int count = [[obj objectForKey:kPatternCount] intValue] + 1;
[obj setValue:[NSString stringWithFormat:#"%i",count] forKey:kPatternCount];
return YES;
}
}
[self.myArrayOfDictionary addObject:[self createANewDictionaryRecord:pattern]];
return NO;
}
-(void)testData
{
NSMutableDictionary *newDict = [self createANewDictionaryRecord:#"mmm"];
[self addANewPatternToArray:newDict];
}
-(void) printArray
{
for (NSMutableDictionary * obj in self.myArrayOfDictionary)
{
NSLog(#"mydictionary: %#", obj);
}
}
- (IBAction)buttonPressed:(id)sender
{
if ([self existingPatternLookup:#"abc"])
{
[self printArray];
} else
{
[self printArray];
}
}
Not being an objective C expert but solving this problem in java before, I would say a dictionary(I used a map when doing it in java) is the best way. Check if the key(pattern) already exist if so increment that count else put a new one in the dictionary.
EDIT
If you want to not just get the count of a pattern, but in fact tell which words fall under that pattern, I would use a dictionary of strings to mutable arrays. In the arrays you store the words and the key to the array is the pattern(as a string), similar code as above but instead of just incrementing the count, you have to add the new word to the array.
The only difference in NSDictionary and NSMutableDictionary is that one can have objects added to it. I think your implementation is good, but English is a complex language. It would be more efficient to parse out the string with regex than to set a key for it.
Why don't you use NSCountedSet instead:
NSCountedSet Class Reference
..which is available in iOS 2.0 and later?
Each distinct object inserted into an NSCountedSet object has a counter associated with it. NSCountedSetkeeps track of the number of times objects are inserted [...] Thus, there is only one instance of an object in an NSSet object even if the object has been added to the set multiple times. The count method defined by the superclass NSSet has special significance; it returns the number of distinct objects, not the total number of times objects are represented in the set.
Then use:
- (NSUInteger)countForObject:(id)anObject
Use a dictionary of NSMutableArrays, and check for the existence of each search key as you recommended. If the key doesn't exist, add an NSMutableSet or NSMutableArray (depending on your needs) for the searched key type "-m-m" for example, and then add to the set or array for that key.

Resources