Strange problem with NSMutableArray - Possibly some memory corruption - iphone

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.

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 do memory management properties affect cells of an array?

In my iPhone development book, I'm seeing some strange coding examples in regard to what an array does when objects are added to the array and when the whole array is released. One code example has the following properties on an instance array:
#property (nonatomic, retain) NSMutableArray* myArray;
The author adds an object to the array and, immediately after, releases his pointer to the object. Won't the array cell now point to garbage data? Unless, behind the scenes, the array cell retains the object when added.
SomeObject* someObject = [[SomeObject alloc] init];
[self.myArray addObject:someObject];
[someObject release];
The author also releases the the pointer to the array without first going through each array cell and releasing the individual objects. This is a memory leak unless, behind the scenes, each cell is sent a release message;.
- (void)viewDidUnload {
self.myArray = nil;
[super viewDidUnload];
}
Unless, behind the scenes, the array cell retains the object when added.
Yes, this happens.
... unless, behind the scenes, each cell is sent a release message.
This also happens.
You have answered your own question.
Here is a quote from Collections Programming Topics:
And when you add an object to an
NSMutableArray object, the object
isn’t copied, (unless you pass YES as
the argument to
initWithArray:copyItems:). Rather, an
object is added directly to an array.
In a managed memory environment, an
object receives a retain message when
it’s added; in a garbage collected
environment, it is strongly
referenced. When an array is
deallocated in a managed memory
environment, each element is sent a
release message.
Unlike in C or C++ where you constantly worry about whether to delete an object or not for the fear of it is still being used somewhere else, Objective-C (or rather it's actually Cocoa SDK) uses the mechanism of reference counting or ownership.
You might already know how it works but you need to also know that in Cocoa, if an object A needs to use another object B it should own (i.e. retain) it. That object A should not rely on some other object C already retained B, because it cannot know when C releases it. So in your case, since NSArray needs to use all objects added to it latter during its lifetime, it needs to retain all the objects. And because of that, when the array is de-alloc-ed, it needs to release them.
This concept of "you need to retain what you want to use latter" is very important when you are dealing of lots of objects.
There are several places in apple development guides that explain that is a good practice to take the ownership of an object (send a retain message) if you plan to use it later. You should do it so that the object is not destroyed while you still might need to access it.
Considering that, you were right assuming that the NSArray retains the object when it is added to the collection, as it still might try to access it afterwards.
You can check the Memory Management Programming Guide
When you add an object to a collection such as an array, dictionary, or set, the collection takes ownership of it.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW3
or the Collections Programming Topics for more details
... In a managed memory environment, an object receives a retain message when it’s added.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Arrays.html#//apple_ref/doc/uid/20000132-SW1
You're right on the first point. When an object is added to an array, the array retains the object. Thus, for an object that has been previously retained, it is necessary to release it after adding it to the array or you can end up with a memory leak.
Likewise, when an object is removed
from an array, the array releases the
object. So, if you want to keep it,
you'll need to retain it.
When an array is released, as you
surmised, the array will release all
the objects it contains. Thus,
releasing each object individually is
not necessary and, in fact, would
raise an exception.
Finally, regarding the line of code
in -viewDidUnload that you quoted:
self.myArray = nil;
This works properly with regard to memory management as long as the myArray property was synthesized as follows:
#synthesize myArray;
Synthesizing creates a setter that effectively does the following:
- (void)setMyArray(NSMutableArray *)anArray
{
if (![myArray isEqual:anArray]) {
[myArray release];
myArray = anArray;
[myArray retain];
}
}
So, when called, the above setter will first release the old array (as long as it's not the same object as the new array.) Then, it will retain the new array, which in this case is nil. Note that retaining nil will just do nothing, and won't trigger an error.
Of course, if you don't synthesize the myArray property, or if you override the setter, you will have memory problems unless you also release the old value & retain the new in your setter.

removeAllObjects not removing if action is fast

I am using a search bar in my app and display some results below from an ext API.
The contents first get stored in an array "xyz" and each time the user types in the search bar, I removeAllObjects and reload the table.
The results are correct if the user types slow i.e. [xyz removeAllObjects] works fine...However if the user types very fast, [xyz removeAllObjects] does not seem to have any effect and duplicate items get appended to the array..
I am not sure how to fix this. Please help me. Thank you.
removeAllObjects is an entirely serial operation; that method doesn't return until the array is empty.
Therefore, there must be a thread in play and you are quite likely accessing a mutable array from multiple threads. Mutable arrays aren't thread safe. Fix the exclusivity and you'll fix your problem.
The easiest way is to separate the array being displayed from the array being computed. As soon as the computation is done, move the computed array to the display array and never mutate it again.
Why not create a new NSArray, point the results at that, and then release the old array. That way having duplicates will be impossible. Something like:
NSArray *newArray = [someObject newSearchResults];
NSArray *oldArray = xyz;
xyz = [newArray retain];
[oldArray release];

Modifying original data from detailView?

I'm working on iPhone and I'm using navigation.
I have list of data in RootViewController, and pass one data to detailViewController when a cell is clicked. Like this,
detailViewController.message = [tableData objectAtIndex:indexPath.row];
And I want to modify the content of 'message' in detailViewController. Is that possible?
I've tried that, but I get an error that it's immutable object. How can I do that? Somebody give me a hint. Thanks ;)
Added ------------------------------------------------
Ok. I'll specify the question.
in detailViewController, the message is decleared NSMutableDictionary* type.
and used like this.
NSMutableString *str = [m_message objectForKey:KEY_CONTENT];
[str appendFormat:#"appended!"];
And I've got this message.
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendFormat:'
Can't I just modify it's content like modifying data in c++ using pointer?
I think it would be best to use a delegate pattern for this. Create a DetailViewControllerDelegate protocol that informs its delegate of a changed message. Something along the lines of:
-(void)detailViewController:(DetailViewController *)controller didChangeMessage:(NSString *)message;
You could also directly manipulate the object by using a mutable one (NSMutableString, NSMutableArray etc.), but using a delegate improves reusability and decouples your classes.
EDIT:
The fact that your dictionary is mutable doesn't mean the object inside it are mutable as well. Your string str is probably immutable. Since NSMutableString is a subclass of NSString, the assignment will work though. You should make sure that you put a mutable string in the dictionary, or use the mutableCopy method of NSString to get a mutable copy of it.
It depends on what type of object you are passing. Immutable means that you cant alter the object. If you for exaple use NSArray, you have to switch to NSMutableArray instead. The same for string or dictionary.
Okay, i think i figured it out. The documentation for appendFormat says that appendFormat is for appending objects, just like when you use stringWithFormat.
The documentation states that:
The appended string is formed using
NSString's stringWithFormat: method
with the arguments listed.
You should use appendString to get the result you want.

I have to retain a NSMutableArray although it's a property

I'm new, but I read a lot about memory management, and really tried to find the answer myself.
It sounds so basic and yet I apparently don't get it.
I have a NSMutableArray as property in .h:
#property (nonatomic, retain) NSMutableArray *documentListArray;
I synthesize it and release it in (void) dealloc.
To populate the array, I have a method - (void)updateRecordList and in there:
self.documentListArray=[DocumentDatabase getDocumentListSortedByDate];
EDIT:next line:
[[self recordListTableView] reloadData];
where DocumentDatabase is a different class with the class methods getDocumentListSortedByDate and getDocumentList.
Here is what is happening in getDocumentListSortedByDate:
NSMutableArray *returnArray = [DocumentDatabase getDocumentList];
//sorting...
NSLog("array count:%i",[returnArray count]); //returns correct numbers first and second time
return returnArray;
and in getDocumentList
NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:files.count];
//add file data to array...
return returnArray;
This works the first time I call updateRecordList, but after adding a file and calling updateRecordList a second time, it crashes with (using NSZombies):
* -[NSCFNumber dealloc]: message sent to deallocated instance 0x7504c90.
With a lot of logging I narrowed the problem down to the line above in updateRecordList and it works if I change it to:
self.documentListArray=[[DocumentDatabase getDocumentListSortedByDate] retain];
My conclusion is that the array down in getDocumentList has been autoreleased before it arrives. So my questions are:
1. Why do I have to retain it there? Shouldn't that happen by itself by declaring the property (retain)?
Or, in other words, why is the array autoreleased too early (assuming this is what is happening)?
2. When I assign a new array to self.documentListArray, is the old array automatically released? If I try to release it myself before getting a new documentList, it crashes too.
Thanks in advance for any reply.
EDIT:
Maybe I'm an idiot: I failed to mention that documentListArray is the data source for an UITableView (see the added line on top). I suspect that I am doing something wrong with populating the table view, and the array gets retained...? It does however crash on assigning the property, not on reloadData.
I go back to study if I use the UITableViewDataSource protocol properly. Thanks to everybody, your answers brought me hopefully on the right track. Will update when solved.
EDIT2:
It works now without retaining, and I think I understand why: I debugged extensively and found that Objects contained in Objects added to the array where nil. Particularly, deep down in encodeWithCoder I did not use "self" when assigning values. When decoding, those values where nil. Since I changed that, it seems to work.
I suspect that not assigning the new array caused the crash, but the TableView which would read the new array-even before I call reloadData. Which would lead back to Davids question of synchroneous access. Thank you all for your help.
The code you've shown it appears correct; it should not be necessary (or correct) to call retain yourself, as long as you are assigning the value to a property with retain semantics before the autorelease pool is drained. Are all the calls (getDocumentListSortedByDate, getDocumentList) happening synchronously, or are you doing any of this in the background? Double-check that you're assigning using the "self." ("self.documentListArray =") instead of just assigning directly to the instance var ("documentListArray ="); if you omit the "self.", the setter is bypassed.
No, don't free the old value before assigning; that's the setter's job.