Can setValuesForKeysWithDictionary be used with a nested dictionary - objective-c

So I have an NSDictionary where one of the keys is an array of dictionaries. The class I'm mapping to has matching key names and setters. Can setValuesForKeysWithDictionary fill the sub-dictionaries for me? When I tried it, it seemed like it filled the objects with pointer junk or something, but I'm a newbe, so maybe I'm doing something wrong. Does that function work like that?

I realized that there was no way for setValuesForKeysWithDictionary to know what kind of object to fill the NSMutableArray with. I ended up making a custom setter for the array property that manually loops the elements of the array (of NSDictionaries) you pass in and calls setValuesForKeysWithDictionary for each one.
Here's the code:
There is a property called itemList of type NSMutableArray that I want filled it objects of type Item. The setItemList setter loops through the array of mystery objects, converting each NSDictionary to my Item type and adds them to a new array. Any comments on how to simplify the code would be welcome.
I also want to add some logic here to handle a situation where the array already contains Item objects instead of dictionaries. In actionscript you can check for null after you try to cast something to see if it worked, not sure what the equivalent process would be here. [item isMemberOfClass [Item class]] always evaluates to YES, even if item is an NSDictionary. I can't understand why...
- (void) setItemList:(NSMutableArray*)input{
[itemList autorelease];
itemList = [[NSMutableArray alloc] initWithCapacity:input.count];
//loop through the array, creating an Item for for each object in the array
for(int i=0;i<input.count;i++){
Item* item = [Item new];
[item setValuesForKeysWithDictionary:(NSDictionary*)[input objectAtIndex:i]];
[itemList insertObject:item atIndex:i];
}
}
- (NSMutableArray*) itemList{
return itemList;
}

Related

Passing a simple NSMutableArray change original

I am having hard time with a simple array that i want to pass .
I have a class with some NSMutableArray that i pass to another class(the array is global from singleton)
[mgzm saveWithArray:[Globals sharedGlobals].allImages];
To this function :
-(void)saveWithArray:(NSMutableArray*)currentArray
{
dataToSave=[[NSMutableArray alloc] init]; //local
dataToSave=[currentArray mutableCopy]; //copy
Than i saw that is is changing the original array which i don't want .
So i did this :
dataToSave=[[NSMutableArray alloc] initWithArray:currentArray copyItems:YES];
Which result in a situation that i can't change the dataToSave array get get a crash when trying to.(it needs to be changed).
Than i did this :
for(NSMutableDictionary *dic in currentArray)
[dataToSave addObject:dic];
Which again if i change dataToSave it change also the original array (?! )
Is there a way in this language to COPY array without changing the original one ????
When you make a copy of a mutable array, changing the array copy does not change the original array, not the objects inside the array. Here is what happens when you call [currentArray mutableCopy]:
The two arrays are pointing to the same objects. If you remove an object from the copy, the original array would still have it. However, if you modify the object itself (say, change the name of A to X) the change will reflect on the object in the original array, because it is the same object.
Here is what you want to happen:
Now the two arrays are completely independent of each other. This is the effect that you achieve when you call
dataToSave=[[NSMutableArray alloc] initWithArray:currentArray copyItems:YES];
However, there is a catch: in order for this to work, the objects inside the array must conform to NSCopying protocol, otherwise the code is going to crash.
To fix this, make sure that the objects inside NSMutableArray implement NSCopying. Here is an answer that explains how it is done.
The problem is although you are creating a new array the NSDictionary objects within the new array are still the same ones. So you need to make copies of the NSDictionary objects, you we're close but you need to do something like this...
-(void)saveWithArray:(NSMutableArray*)currentArray
{
dataToSave=[[NSMutableArray alloc] init]; //local
for(NSMutableDictionary *dic in currentArray)
[dataToSave addObject:[NSDictionary dictionaryWithDictionary:dic];
}

Grab Object Propertys from NSMutableArray Objective - C VS C++

Hey there I'm new to objective c is there any way to grab and objects properties once it's in an NSMutable array.
like this:
so in c++ it would look like this
for (int i = 0; i < length; i++)
{
someArray[i].someClass.somePropertyInTheClass;
}
is there any possible way to do that with an NSMutableArray in OBJECTIVE -C
Thanks in advance all you pro objective c-ers!
There are two main ways to loop through an array in Objective-C. First, using an index:
NSInteger count = [array count];
for (int i; i < count; i++)
{
id object = [array objectAtIndex:i];
NSLog(#"%#", [object somePropertyInTheClass]);
}
Note that the the count is stored in a variable rather than in the for loop. This avoids having to recalculate the count each time through the loop.
A more concise method is with fast enumeration:
for (id object in array)
{
NSLog(#"%#", [object somePropertyInTheClass]);
}
Both versions are semantically equivalient, they both log each object's somePropertyInTheClass property in the array (assuming each object has a somePropertyInTheClass property). In both versions, id can, and should, be replaced with a specific class, eg NSDictionary * based on what you store in the array.
While fast enumeration is more concise, the approach with the counter is useful if you need to use the index for something other than accessing one array. Also, fast enumeration does not allow you to modify the array, even in another method, while looping. In most cases though, when iterating through an array, fast enumeration can be used.
Hey there I'm new to objective c is there any way to grab and objects
properties once it's in an NSMutable array.
The mere fact of being included in an array or other container doesn't prevent you from accessing the properties of an object. If the object you want is at index i, you can get the object simply:
Person *person = [arrayOfPeople objectAtIndex:i];
or even simpler:
Person *person = arrayOfPeople[i];
You can then of course get the property like this:
NSString *name = [person valueForKey:#"name"];
or just:
NSString *name = person.name;
However, your example shows a loop, suggesting that you might want to get the same property of all the objects in an array. Objective-C containers have the very nice property that they respond to -valueForKey: by getting the value for the given key from each contained object and returning a container with just those values. So, you can say:
NSArray *names = [arrayOfPeople valueForKey:#"name"];
and you get an array of names in names, with one name for each object in the array arrayOfPeople.
You can, of course, also iterate over the array:
for (Person *person in arrayOfPeople) {
NSString *name = person.name;
NSLog(#"The name is %#", name);
}
Finally, you should know that mutable arrays work just the same way as non-mutable arrays when it comes to accessing objects. The only difference between a mutable array and a non-mutable array is that you can add or remove objects from a mutable array after you create it. The mutability of the objects contained in the array isn't affected by the array's own mutability. That is, if you have an array arrayOfPeople, and if the Person objects stored in it can be modified, then you're free to change the name, age, etc. of any object stored in the array regardless of whether arrayOfPeople is mutable or non-mutable.

Updating values on NSArray

I'v run into such problem. I need to update the values in my NSArray. And don't know a way to do it. Here's my array
NSArray *arrayWithInfo = [[NSArray alloc] initWithObjects:AMLocalizedString(#"Status", nil),AMLocalizedString(#"Call", nil),AMLocalizedString(#"Location", nil),AMLocalizedString(#"Control", nil),AMLocalizedString(#"Sim", nil),AMLocalizedString(#"Object", nil),AMLocalizedString(#"Info", nil),nil];
self.dataArray = arrayWithInfo;
[arrayWithInfo release];
To be more specific I have tableview initialized with this array. There is a possibility for user to use different localized strings, so I have to update it. By using [tableview reloadData]; i'v got the table to update, but the values in NSArray stay the same as they were initialized in first place.
So how to make array look up at the strings once again and get their new values?
Use NSMutableArray instead of NSArray
NSMutableArray (and all other classes with Mutable in the name) can be modified.
You should be using an NSMutableArray. Doing so will allow you to change its values after instantiation.
Your array doesn't need to be mutable here as the array seems to be all or nothing. You dont mention the requirement to delete some objects and not others. NSMutableArray isn't needed. You want to write a lazy loading getter method for the array which reinstantiates it if the array doesnt exist.
-(NSArray *)dataArray{
if (_dataArray){
return _dataArray;
}
_dataArray = NSArray *arrayWithInfo = [[NSArray alloc] initWithObjects:AMLocalizedString(#"Status", nil),AMLocalizedString(#"Call", nil),AMLocalizedString(#"Location", nil),AMLocalizedString(#"Control", nil),AMLocalizedString(#"Sim", nil),AMLocalizedString(#"Object", nil),AMLocalizedString(#"Info", nil),nil];
return _dataArray;
}
Then when you want to reload the tableView
self.dataArray = nil;
[tableView reloadData];
this destroys the old array, forcing it to be remade but with the new localisation.
EDIT:
The issue is the array isn't storing the statement AMLocalizedString(#"Status", nil) its storing the result of that statement, which is the localised string itself. There is no way to make the array re-evaluate that statement without either re-creating the whole array again or using an NSMutableArray and changing all the objects. The lazy loading getter method is more in the objective-c style.
You need to use the NSMutableArray. The NSArray is immutable.

Is there any way to specify the class of objects of a NSMutableArray?

Im having the following problem:
I've made a NSMutableArray "array" that is going to contain objects of a class named "Class". At the start that array should be empty and it must be filled during the program's execution.
As I never actually told the compiler that my NSMutableArray will be holding elements of the class Class, when I try to write the appropriate methods the compiler wont let me do it.
This is my first experience on Objective-C and iPhone development. I used to code in C/C++ where I declared my arrays in the following way:
Class array[NUMBEROFELEMENTS];
Is there any way to do this in Objective-C?
Thanks!
The truth is that is doesn't matter to the NSMutableArray what type of object it is. NSMutableArray simply stores pointers to all the objects they contain, or reference.
The trick is when you pull the object back out of the array you need to create a new pointer based on the appropriate type:
MyObject *myObject = [myArray objectAtIndex:0];
Then you can use the object however you like:
[myObject doThatThingWithThisValue:10];
Or whatever you need.
Arrays in Objective-C Cocoa are objects (as well as other collections, sets, dictionaries). Arrays can contain references to objects of any type, so the type for the array is simply NSArray, NSMutableArray, etc...
Since they are objects, you can send them messages to manipulate their content.
I suggest you take a look at Apple's excellent Collections Programming Topics, which explain the rudiments of collections.
Here is a quick example :
// two objects of different types
NSNumber *n = [NSNumber numberWithInteger:10];
NSString *s = #"foo";
// alloc/init a new mutable array
NSMutableArray *a = [NSMutableArray arrayWithCapacity:10];
// add an object
[a addObject:n];
[a addObject:s];
// array a now contains a NSNumber and a NSString
Well, you can still have C-style arrays in Objective-C.
However, the characteristics of Objective-C (some people will call it strength, other will call it weakness) is that it has dynamic typing of objects and dynamic dispatch.
It has NSArray and NSMutableArray which are not specialized for the certain class. It can store objects of non-compatible classes.
You can use the following idiom: [obj isMemberOfClass: [Class type]] to make sure an array element is of the desired type and then cast to Class*.
You can also use for-each loop (aka Fast Enumeration):
NSMutableArray* array = //... initialize your array
for (Class* elm in array) {
elm.your_property = 10;
}

NSMutableArray add object with order

I have a NSMUtableArray which has elements, for example:
a,b,c,e
And I want to add an object d to behind c and before e.
In other words, I'd like to insert an object to a sorted array.(The object can be a custom object, too)
I'd like to know : besides using for to find the position, is there any other method to implement it? It is better to use the iOS api.
Thanks.
You can use -[NSArray indexOfObject:inSortedRange:options:usingComparator:] to ask an NSArray for the index where an object should be inserted given an array range that’s currently sorted.
For example, assuming the entire array is sorted::
NSMutableArray *array = …;
id newObject = …;
NSComparator comparator = …;
NSUInteger newIndex = [array indexOfObject:newObject
inSortedRange:(NSRange){0, [array count]}
options:NSBinarySearchingInsertionIndex
usingComparator:comparator];
[array insertObject:newObject atIndex:newIndex];
Since this method uses binary search, it is more efficient than iterating over all elements in the array.
The comparator is a block object that receives two objects of type id and returns an NSComparisonResult value.
To inject element to known index (position) use
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html
And to find position of object previously placed into NSMutableArray use
- (int)indexOfObject:(id)anObject
NSMutableArray - Get Arrays Index Integer By Searching With A String
Section Finding Objects in an Array
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html
I'd just add the new object at either end and sort the array again. If the array you're adding to is already sorted, the re-sort that moves one object is going to be about as quick as anything you'd implement yourself.
NSMutableArray *things; // populated
id newObject;
...
[things addObject:newObject atIndex:0];
[things sortUsingSelector:#selector(compare:)];