NSMutableArray object thinks it is an NSArray :( - iphone

So I have a property NSMutableArray *grades. At the only place where I set this property, I am doing this:
NSMutableArray *array = [[NSMutableArray alloc] init];
self.grades = array;
[array release];
[self.grades addObject:#"20"];
The last statement generates an exception: -[NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'.
What in the world am I missing?

It sounds like the property is set to copy, which means the synthesized accessor makes an immutable copy of the array

Make sure grades is a NSMutableArray.
Edit:
copy returns an immutable copy, so you can't make changes. From Apple's Objective-C docs:
Copy
If you use the copy declaration attribute, you specify that a value is copied during assignment. If you synthesize the corresponding accessor, the synthesized method uses the copy method. This is useful for attributes such as string objects where there is a possibility that the new value passed in a setter may be mutable (for example, an instance of NSMutableString) and you want to ensure that your object has its own private immutable copy. For example, if you declare a property as follows:
Although this works well for strings, it may present a problem if the attribute is a collection such as an array or a set. Typically you want such collections to be mutable, but the copy method returns an immutable version of the collection. In this situation, you have to provide your own implementation of the setter method, as illustrated in the following example.
Copying the entire collection on assignment is a heavy operation. Are you sure you don't want to retain the collection, or just assign it?
If you really want a mutable copy, then write your own setter as the docs suggest.
- (void)setGrades:(NSMutableArray *)array {
// make shallow/deep copy here, and assign to `grades`, not `self.grades`
}

What is grades declared as?
From the looks of the error message your declaring grades as an NSArray and while this is valid it does mean that you lose the mutability of the array.
To maintain the array as mutable you'll need to declare grades as an NSMutableArray as well.
edit:
In light of your edit the reason could be that your using the copy keyword in the property, this would mean that when your assigning the array using self.grades the synthesised setter method makes an immutable copy of array

self.grades probably returns an NSArray if declared as #property NSArray* grades seeing this the compiler freaks and does not want to support addObject: method. You have 2 options
cast it
like [(NSMutableArray*)self.grades
addObject:].
add the object before assigning the
array.

Related

How to declare array of pointers in objective c

I dont know how to declare a array which just stores pointers to objects. As per My understanding ,if I use method
[ someArray addObject:someObject ] ,
It would then add the copy of object to array and any changes to object wont get reflected to original object.
What I want is that create a array of pointers which would just point to objects and changes made to objects would persist. pardon me, If I am missing something basic.
An NSArray or NSMutableArray is an array of pointers. No copying is done.
you have your basics wrong. technically when you do that you create the array of pointers to those objects.
http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html read the description.
If you want to get the object copied you have to explicitly say so.
Look at this question for example
Deep copying an NSArray
By the way you should use an NSMutableArray.
Also look at the superclass NSArray
http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html#//apple_ref/occ/cl/NSArray
specifically for the initWithArray:copyItems:
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.
By default adding an object to a nsmutablearray increases its capacity if necessary, adds a retain for the object, and the pointer to the object.
...if I use method
[ someArray addObject:someObject ] ,
It would then add the copy of object to array and any changes to
object wont get reflected to original object.
While it technically doesn't pertain to the question, I simply must correct your terminology. "Copy" in Objective-C implies that the method -copy is sent to the object, which would create a new object in of itself. What Arrays do is send -retain to their objects, which means that the array itself now owns a stake in the object, which is why changes that don't reference the array (-objectAtIndex:), or have a valid claim to the object itself are not reflected.
What I want is that create a array of pointers which would just point
to objects and changes made to objects would persist. pardon me, If I
am missing something basic.
Well, unfortunately iOS does not support the class NSPointerArray, which would make your life significantly easy in regards to an actual array of pointers. Without getting into any C-craziness, I can only reiterate what I mentioned above: If you need to mutate an object in an array, just access it with a valid reference to it, or use -objectAtIndex. So long as you still have a valid claim on the object (a reference in this case, it's pointer didn't change because it was sent -retain) you can change it. Note the simple example below:
NSMutableString *str = [[NSMutableString alloc]initWithString:#"Hello"];
NSArray *arr = [[NSArray alloc]initWithObjects:str, nil];
NSLog(#"%#",arr);
[str appendString:#" Friend!"];
NSLog(#"%#",arr);
This prints:
2012-08-07 21:37:46.368 .MyApp[2325:303] (
Hello
)
2012-08-07 21:37:46.369 .MyApp[2325:303] (
"Hello Friend!"
)
Simple!

How does calling retain in different ways on the same object work?

I want to know difference between following two:
NSMutableArray *myArray = [[someObject returnMutableArray] retain];
and
NSMutableArray *myArray = [someObject returnMutableArray];
[myArray retain];
I have some complex data flow project in which I have to return different NSMutableArrays.
I also want to know what is the best way to return NSMutableArrays.
There is no difference apart from how you want your code formatted.
The reason this works is in the documentation for NSObject
As a convenience, retain returns self because it may be used in nested expressions.
Therefore retain returns the object that is was called upon (a mutable array in your case) which means you can nest methods or simply use the return value in the assignment as you have in your example.
For returning values from methods you should make sure it is autorelease'd
So using your snippet
- (NSMutableArray *)myMethod;
{
NSMutableArray *myArray = [someObject returnMutableArray];
// ... do some work
return myArray;
}
Because the method returnMutableArray does not contain the keyword's alloc, new or copy it should be made to return an autorelease'd object. Now as we are returning the object at the end of the method we don't need to take any further retains as it will be ready for returning.
If you are unsure on memory management you should read the Advanced Memory Management Guide or (preferably) start using ARC
There is no difference between 1 and 2.
The best practice on iOS is to return autoreleased objects from methods, and there should be no need to retain them.
If you are confused about how retain and release work, you should probably just enable ARC in your project, which manages retain and release for you automatically.

Appropriate way to set property for NSMutableArray

I want a mutable array and set it by a property, which alternate is preferable and please explain the reason. I have the 2 alternatives
NSMutableArray *arrSubTitles_temp = [[NSMutableArray alloc] initWithObjects:
#"String 1",
#"String 2",nil];
self.arrSubTitles = arrSubTitles_temp;
[arrSubTitles_temp release];
OR
NSArray *arrSubTitles_temp = [[NSArray alloc] initWithObjects:
#"String 1",
#"String 2",nil];
self.arrSubTitles = [arrSubTitles_temp mutableCopy];
[arrSubTitles_temp release];
I guess the 1st one is better, as self.arrSubTitles property is retained in .h, so (in 2nd) mutableCopy method will provide the mutable array, but also the retain count will be 2 in this case.
Which method is preferable, should I use retain in .h while setting the property or just assign. Please suggest.
Many thanks in advance :)
Use retain as your property attribute, unless you have a good reason not to (ex: retain would cause a retain cycle, it's a primitive, you need to guarantee the object is immutable, etc)
Use the first example you posted, since the second one would leak memory.
If you use assign as your property attribute, then the first option would probably crash:
Allocate an array (owned by you)
Assigned to a property (still owned by you)
Release (no owners, promptly deallocated)
Attempt to access property value: crash (because the pointer is stale)
The second one, however, would work:
Allocate an array (+1 owners)
Copy the array (original: +1 owners, copy: +1 owners)
Assign the copy into the property (both still have +1 owners)
Release the original array (it gets deallocated, the copy continues to exist)
Regardless, it is rather unconventional to have an assign property and then manage the retention of the value yourself. It is extremely error-prone, and much simpler to declare the property as retain and let the generated setter take care of the release/retain dance for you.
Either way is problematic because the caller must provide a mutable array. If the caller ever passes an immutable array (as anything that uses KVC to set the property would be able to do without a compiler warning), you will find yourself holding an immutable array in a mutable-array property, and will shortly thereafter try to mutate it, causing an exception.
What I do is hold a mutable array, which I create in init and release in dealloc, as the value of the property, declare the property as #property(nonatomic, copy) NSArray *myArray, and implement setMyArray: to send a setArray: message to my mutable array. At no point do I ever switch out the array; I exclusively and privately own the same mutable array for the entire lifetime of my object.
An equivalent implementation of setMyArray: would release the array and set the myArray variable to a mutableCopy of the input array. The only difference is that this would create and throw away more arrays over the duration of the process.
With either of these solutions, the caller does not need to worry about whether it passes a mutable or immutable array; the property will always do the right thing. And the caller would, as usual, not need to retain it on my behalf.
Note that a setter implementation generated by #synthesize will not do the right thing. It sends copy to the input array, which will return an immutable copy. This would be even worse, as then it would not work even if the caller does pass in a mutable array. You must implement a custom setMyArray: accessor to correctly handle both immutable and mutable arrays.
What about the setting it as autorelease
NSMutableArray *arrSubTitles_temp = [[[NSMutableArray alloc] initWithObjects:
#"String 1",
#"String 2",nil] autorelease];
self.arrSubTitles = arrSubTitles_temp;
[arrSubTitles_temp release];

Strange problem with NSMutableArray - Possibly some memory corruption

I am trying to update data in a table view using a NSMutableArray. Quite simple :(
What is happening is that I get my data from a NSURLConnection Callback, which I parse and store it in an array and call reload data on the table view. The problem is that when cellForRowAtIndexPath is called back by the framework. The array still shows the correct count of the elements but all string objects I had stored earlier are shown as invalid.
Any pointers
Maybe your problem is something like the below
NSString *value = [NSString stringWithFormat:#"%#",stringFromWebService];
[arrayOfObjects addObject:value];
[value release]; // This should not be released
This may not be exact but could be similar. Here value is obtained from class method of NSString which is an autoreleased object so if you can see it will be released twice, one by autorelease and other by you.
This is the area you need to check.
Check that you are retaining the NSString objects in your NSURLConnection callback. Are you autoreleasing them?
Edit
Ok, forget that last thing. Double checking myself, NSMutableArray will automatically retain the objects when you add them to your array. So you won't need to retain them explicitly:
Like NSArray, instances of
NSMutableArray maintain strong
references to their contents. If you
do not use garbage collection, when
you add an object to an array, the
object receives a retain message. When
an object is removed from a mutable
array, it receives a release message.
So you need to check you aren't doing any other explicit releases on the objects you are adding to the array. Are they referenced anywhere else?
The problem is there where you are adding the string object to a mutable array. The string object was already invalid that time. That's why the time you are accessing them from the array, they are invalid or do not exist.
So best thing is to check the code where you are adding the string object during the parsing.
Your problem may be that you have not initiated the array correctly.
Are you using the array as an attribute of the class?
Make sure when you load the view you allocate and initiate the array.

Should I alloc an NSMUtableArray instance variable?

This is probably a silly question but I have been thinking it over for a while with no obvious answer.
I have a small app that I have been working on and am having a problem with my NSMutableArray instance variable. It was always (null) until I added an [[NSMutableArray alloc]init] to the viewDidLoad.
I am pretty new to the Objective C world so I am trying to get an understanding of this issue. I was under the impression that with I instantiated my class the instance variables were all alloc'd. When I add items to the array without the alloc/init it remains (null) with a retain count of 0.
The array in question was declared as a (retain) property.
I can add code if this isn't clear.
Any instance variables that are objects are actually just pointers that are initialized to nil (0). That is why the item isn't retained and added to the array, since messages to nil objects return nil/0.
You need to alloc and init the object in your class's init, and then release it in the dealloc.
The retain/assign/copy qualifiers on the property declaration are about how the memory for the property value is managed in the getters and setters that the compiler synthesizes for you. (The documentation discusses them in detail, and gives example code for each kind.)
That's completely orthogonal to whether your instance variables are initialized for you or not. Declaring an ivar is just reserving storage for the value; for Objective-C classes, that's a pointer to an instance. The runtime will initialize those ivars to zero for you, but you're still responsible for creating the objects you want to store there. (The same is true in similar languages like Java or C#: declaring an Array instance variable just gives you space for a reference, it doesn't create the array for you.)