Objective-C accessing / changing array elements in a multidimensional array (NSArray) - objective-c

I'm trying to change a value in a multidimensional array but getting a compiler error:
warning: passing argument 2 of 'setValue:forKey:' makes pointer from integer without a cast
This is my content array:
NSArray *tableContent = [[NSArray alloc] initWithObjects:
[[NSArray alloc] initWithObjects:#"a",#"b",#"c",nil],
[[NSArray alloc] initWithObjects:#"d",#"e",#"f",nil],
[[NSArray alloc] initWithObjects:#"g",#"h",#"i",nil],
nil];
This is how I'm trying to change the value:
[[tableContent objectAtIndex:0] setValue:#"new value" forKey:1];
Solution:
[[tableContent objectAtIndex:0] setValue:#"new val" forKey:#"1"];
So the array key is a string type - kinda strange but good to know.

NSMutableArray *tableContent = [[NSMutableArray alloc] initWithObjects:
[NSMutableArray arrayWithObjects:#"a",#"b",#"c",nil],
[NSMutableArray arrayWithObjects:#"d",#"e",#"f",nil],
[NSMutableArray arrayWithObjects:#"g",#"h",#"i",nil],
nil];
[[tableContent objectAtIndex:0] replaceObjectAtIndex:1 withObject:#"new object"];
You don't want to alloc+init for the sub-arrays because the retain count of the sub-arrays will be too high (+1 for the alloc, then +1 again as it is inserted into the outer array).

You're creating immutable arrays, and trying to change the values stored in them. Use NSMutableArray instead.

You want either NSMutableArray's insertObject:atIndex: or replaceObjectAtIndex:withObject: (the former will push the existing element back if one already exists, while the latter will replace it but doesn't work for indices that aren't already occupied). The message setValue:forKey: takes a value type for its first argument and an NSString for its second. You're passing an integer rather than an NSString, which is never valid.

Sorry for responding 1 and half years old question :D
I got the same problem, and at last I solved it with counting the elements, then do addObject to push to the array element

Related

initWithArray vs initWithArray copyItems [duplicate]

This question already has answers here:
Deep copying an NSArray
(6 answers)
Closed 9 years ago.
I have a question what's the difference between these two methods on initializing an array?
I am assuming copyItems will provide a deep copy?
When would you use one versus the other?
Thank you!
The documentation for these methods is the first result (for me) with a little Google search.
initWithArray: copyItems:
has this documentation:
Initializes a newly allocated array using anArray as the source of data objects for the array.
Parameters
array
An array containing the objects with which to initialize the new array.
flag
If YES, each object in array receives a copyWithZone: message to create a copy of the object—objects must conform to the NSCopying
protocol. In a managed memory environment, this is instead of the
retain message the object would otherwise receive. The object copy is
then added to the returned array. If NO, then in a managed memory
environment each object in array simply receives a retain message when
it is added to the returned array.
whereas initWithArray: has this documentation:
Initializes a newly allocated array by placing in it the objects contained in a given array.
e.g.
Note: Since NSArray isn't mutable, my corresponding implementations aren't directly usable
`array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES]`
//would correspond to:
array2 = #[
[array1[0] copy],
[array1[1] copy],
[array1[2] copy],
...
[array1[n] copy],
]
whereas
array2 = [[NSArray alloc] initWithArray:array1]
//would correspond to:
array2 = #[
array1[0],
array1[1],
array1[2],
...
array1[n],
]
//or
array2[0] = array1[0];
array2[1] = array1[1];
array2[2] = array1[2];
...
array2[n] = array1[n];
initWithArray: initializes a new array and places in it all the objects contained in a given array. This means that each object in the given array will receive a retain. Hence, if you edit an object in the new array, you will modify that object even in the given array. (see shallow copy)
On the other hand, initWithArray:copyItems:, if YES is passed as second argument, will provide a deep copy.
Beware that if you need to deeply copy an entire nested data structure then this approach will not suffice. (see the Apple documentation)
Example:
NSMutableString *s = [[NSMutableString alloc] initWithString:#"hello"];
NSArray *a = #[s];
NSArray *b = [[NSArray alloc] initWithArray:a];
[a[0] appendString:#" there"];
after these lines the arrays a and b will contain the mutable string "hello there"
NSMutableString *s = [[NSMutableString alloc] initWithString:#"hello"];
NSArray *a = #[s];
NSArray *c = [[NSArray alloc] initWithArray:a copyItems:YES];
[a[0] appendString:#" there"];
while after these lines the array c will contain the mutable string "hello" and the array a will contain the mutable string "hello there"

Retrieving NSArray From an NSDictionary

I am trying to get an array full of my data, I keep getting an BAD_ACCESS error when I run this though at the calling the array which I have not included here but I even commented that code out and tried just calling it to the log and still get the BAD_ACCESS error. The array is stored in a dictionary that contains a one key that is a number. I am not sure what I am doing wrong here.
ISData *is = [[ISData alloc] init];
NSDictionary *dic = [is getData:#"right" : isNumber];
NSArray *array = [[NSArray alloc] initWithArray:[dic valueForKey:#"2"]];
NSString *out = [array objectAtIndex:0];
How the dictionary is created:
NSNumber* key = [NSNumber numberWithInt:isNumber];
NSArray *values = [NSArray arrayWithObjects:[NSString stringWithUTF8String:name], [NSString stringWithUTF8String:desc], [NSString stringWithUTF8String:intent], nil];
[dic setObject:values forKey:key];
You don't say exactly where it crashes, and you don't have an obvious crashing bug here, so it's hard to diagnose your actual issue. This could be a memory management thing that's outside the code you've presented. But a couple things are going on here that are suspicious:
You should never have a bare [MyClass alloc] without the -init call. Your init should call super's init, which is responsible for setting up the new object.
Your -valueForKey: should be -objectForKey:. The difference is probably unimportant in this case, but the former is used for "KVC" coding, which you're not using. If you set it as object, get it as object.
Your #"2" as the key into the dictionary doesn't match your input, which is an NSNumber. NSNumbers are not string versions of numbers, so you're unlikely to find any value there. Instead, use the same [NSNumber numberWithInt:2] pattern.
It is most likely that your array is empty. You can try print NSLog(#"count = %d", array.count); to see if that's the case.
If your dic is set up in the second block of code, then what's that NSDictionary *dic = [is getData:...] thing in the first block?
And is there a reason you cannot set up your array directly? Is there a reason for you to use a dictionary when it has only one key?

How to copy NSArray to another NSArray?

I have many different NSArrays, and according to the users choice I want one of them to be copied to a new NSArray. How do I copy one NSArray to another?
There can be several ways for this-
array1 = [array2 copy];
Use initWithArray method.
You can also use initWithArray:copyItems: method. (This if for NSMutableArray)
you can use the
NSArray *_newArray = [NSArray arrayWithArray:_oldArray];
or if you prefer better, you can use:
NSArray *_newArray = [[NSArray alloc] initWithArray:_oldArray];
(in that case the object of the first array won't be copied, that get only a retain front he second NSArray, you can remove the object from any array it won't affect the other array, but if you change any object in any NSArray it will be changed in the other one as well because there is both of the old and the new array is working with the same instance of the objects.)
if your plan is to make another instance of the old objects in the new array:
NSArray *_newArray = [[NSArray alloc] initWithArray:_oldArray copyItems:true];
if you are using the ARC, you won't need to do anything else, if you are not, in the case of both -initWithArray: or -initWithArray:copyItems: you should use the [_newArray release]; to release the array after you don't want to use anymore.
As well as
NSArray *newArray = [oldArray copy];
if you need to add/remove from the new array, the simplest way to make a mutable copy is:
NSMutableArray *editableArray = [oldArray mutableCopy];
The above functions both make shallow copies, for deep copy it's as #holex and #rishi mentioned
NSArray *newArray = [[NSArray alloc] initWithArray:oldArray copyItems:true];
NSMutableArray *editableArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:true];

Is this a correct declaration of an Array in Objective c?

NSArray *arr=[[[NSArray alloc]autorelease]autorelease];
Close, but no cigar.
If you want an autoreleased NSArray, you'd need to use:
NSArray *arr = [[NSArray alloc] init] autorelease];
That said, this will simply get you an empty immutable array, so you'll most likely want to populate it via one of the initWithObjects: style methods. (See the full NSArray class reference for more information.)
Or you can just declare it like this:
[NSArray array];
This gives you an autoreleased instance of the array.

Order and release NSArray in Objective-C

I am trying to sort an array of countries. This way works, but I can't figure out the way to release tmpArray. How do I release it and is there a better way of doing this?
// PUT COUNTRIES IN ARRAY
NSString *myFile = [[NSBundle mainBundle] pathForResource:#"Countries" ofType:#"plist"];
NSArray *tmpArray = [[NSArray alloc] initWithContentsOfFile:myFile];
tmpArray = [tmpArray sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
arrayCountries = [[NSArray alloc] initWithArray:tmpArray] ;
// [tmpArray release];
Either -autorelease the one you alloc/init'd (because you're losing your reference to it when you replace it with the sorted array) or use another variable like 'sortedTmpArray'.
What you're currently doing is "create this object and assign it to tmpArray", then "create another array by filtering this one and assign it to tmpArray". At that point, you no longer have a pointer to the first array you created so there's no way to release it - it's leaked.
The solution is to place it in the autorelease pool when you create it or just use two separate pointers. Alternatively, you can create a mutable array the first time and use -sortUsingDescriptors: to sort it in place instead of creating two separate arrays.