NSMutableArray removeObjectAtIndex - iphone

I'm getting the following error when removing from my NSMutableArray
-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x1cdced10
2011-07-13 00:33:14.333 MassText[1726:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x1cdced10'
However right before I remove, I print out the array and the index. Neither are nil and I have no reason to believe why this error would be happening. Any ideas?

I had this problem. Mine was that I accidentally used type casting like this.
NSMutablearray * myarray = [[NSMutableArray alloc] init];
myarray =(NSMutableArray*) [mydictionary allkeys];
This will work for some time.. but if you are in a tight and large loop this tend to fail.
I changed my code to
NSMutableArray * myarray= [[NSMutablearray alloc] initWithArray:[mydictionary allKeys]];

The object is an NSArray, not an NSMutableArray.

You are calling removeObjectAtIndex on a NSArray instance. We can see clearly by your crash log.

At this point, four smart people (not including myself) have pointed out that you're sending -removeObjectAtIndex: to an object that thinks it's an immutable array. This would be a good time to start wondering why the array is immutable when you previously thought it was mutable. If you post some code that shows how the array is created, someone here will probably be able to show you what's going wrong.
One way that you can end up with an immutable array when you thought you had a mutable one is to copy a mutable array. For example, you might have a property:
#property (copy) NSMutableArray *myArray;
Perhaps you then create a mutable array, add some objects, and assign it to your property:
NSMutableArray *tempArray = [NSMutableArray array];
[tempArray addObject:#"You say goodbye"];
[tempArray addObject:#"I say hello"];
self.myArray = tempArray;
Now, does tempArray point to a mutable array or an immutable array? I haven't tested recently, but I'm pretty sure that you get an immutable array. You definitely get an immutableArray if you say:
NSMutableArray *foo = [tempArray copy];
So, start looking for places in your code where your array pointer is reassigned. After all, if your pointer really did point to a mutable array, it'd be awfully hard to explain the exception that you're getting.

The error says that you are trying to call the removeObjectAtIndex selector on an NSArray, which won't respond to that selector.
Make sure the array is really an NSMutableArray, not an NSArray.

I had the same problem, and it was because of the use of the copy method. I made one on my own returning a NSMutableArray* and it worked.

Related

Understanding memory management in ios

I am in the process of learnig objective-c and programming an iPad app. One thing I keep tripping myself up on and having to re-read is memory management. I am getting there...slowly. Basic rules such as for every alloc / retain you must have a release is useful. However, one relatively basic thing eludes me and I wonder if someone could explain...
Take the following code...
NSArray *myArray = [[NSArray alloc] init];
myArray = [someNSSet allObjects];
This is relatively straight forward coding and would require a [myArray release] statement.
However, I keep seeing examples of (and indeed, I have used extensively the following 'short cut'...
NSArray *myArray = (NSArray *)[someNSSet allObjects];
How, as far as I understand when you use the (NSString *) you dont need to use a [myArray release] statement, but I dont understand why.
Could someone possible explain?
NSArray *myArray = [[NSArray alloc] init];
myArray = [someNSSet allObjects];
this code is leaking myArray because you lose the reference to NSArray that you've allocated on the first line; you don't need to alloc here, because on the second line you're assigning a new value to myArray.
NSArray *myArray = (NSArray *)[someNSSet allObjects];
and this code example is perfectly fine, you're assigning the result of [someNSSet allObjects] to myArray pointer and you don't own the returned value, so you don't need to care about releasing it.
Consider using ARC (Automatic Retain Counting) for you project. With ARC the compiler takes care of retain counts so you don't have to, in fact aren't allowed to. There is a refactoring that will convert a current project.
As you said, there is a leak in the first code you posted. so you must add a release:
NSArray *myArray = [[NSArray alloc] init];
[myArray release];
myArray = [someNSSet allObjects];
In fact, when you obtain an object through a method that starts with alloc, new or copy, you own it, and you should release it. That's why, here you should release the array you obtained using the method alloc. This convention makes it easy to know when you own objects and when you don't. So remember: alloc, new or copy.
As for the second example, you obtained the array though a method that doesn't start with one of the three words (alloc, new or copy), so you don't own the object, and you are not responsible of releasing it. In fact, the array you obtained is an autoreleased object, which means that even though its retain count is currently 1, it will be automatically released when something called the autorelease pool is drained.
Here is a reference about Memory Management Rules.
In the first line:
NSArray *myArray = [[NSArray alloc] init]
some amount of memory is allocated for an array (actually in this case it is senseless since the size of the array is 0. Keep in mind that NSArray is immutable!).
The variable myArray holds the address of the first byte of the reserved memory area.
Now in the second line you change the value of myArray which now will point to the first byte of the memory area where [someNSSet allObjects] is stored. At this moment you do not know any more where the array is stored what you've created in the first line. And so you have a leak.
The line:
NSArray *myArray = (NSArray *)[someNSSet allObjects];
is correct, since you do not reserve any memory at this point. If you are not using ARC you might call retain in order to keep GC away from the referenced block of memory. In other way you might receive a BAD_EXEC when the owner of the object releases it and you try to access it through e.g.: [myArray objectAtIndex:0]

Clear a NSDictionary of NSarrays

I spent a lot of time trying hundreds of things, and searching on the internet for my problem, but I didn't find anythig, so I hope you guys will be able to help me :).
So, I have an NSMutableDictionary that I populate with NSArrays when I parse an XML document. My problem is, I want to empty it before I release it because it appears to cause leaks !
Best solution, to my eyes, is : [myDict removeObjectsForKeys : [myDict allKeys]] but the app crashes and I get the following message in the console :
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'
I really can't figure why... any ideas ?
EDIT
Important point I forgot (I guess...), is that the dictionary I'm calling is in my application Delegate, with appDelegate = [[UIApplication sharedApplication] delegate];. (appDelegate defined in my .h with myAppDelegate class type).
Then, I initialize it like this : appDelegate.myDict = [[NSMutableDictionary alloc] init];
Is it wrong ?
What's weird then, is that when I do :
[appDelegate.myDict release];
NSLog( #"%#", appDelegate.myDict);
I get the dictionary filled...
EDIT 2
I just figured out that all my appDelegate variables are not released when I call [appDelegate.myVariable release] ... Wtf am I doing wrong ? This is driving me crazy ><
When you release a dictionary or array it releases all the elements inside it. If you're getting leaks they're not due to a failure to remove the objects.
Of course, in your case part of your problem appears to be that you don't know where the error is occurring. -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0) indicates that you were executing objectAtIndex on an (empty) NSArray, and that doesn't happen (directly) if you do [myDict removeObjectsForKeys : [myDict allKeys]] on an NSDictionary. So you need to figure out where that error is really coming from.
What about this:
// myDict should be NSMutableDictionary
[myDict removeAllObjects];
This should hep you figure out which key (or keys) are pointing to the misbehaving arrays.
for ( NSString *key in [myDict allKeys]) {
NSLog(#" key - %#", key);
[myDict removeObjectForKey: key];
}
NSLog(#" the problem is not with the dictionary...");
You don't need to empty an NSMutableDictionary before releasing. Any objects retained by the dictionary will sent a release message when the dictionary is dealloced.
It sounds as though your arrays are being retained elsewhere, causing the leak. Are you sure you've implemented dealloc methods correctly for all your objects (view controllers, model objects, etc)?

Application crash problem in iPhone

I have used NSMutable Dictionary and NSMutable Array. The datas are to be stored and retrieved from plist(Documents Directory) using NSArray of NSMutable Dictionary.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object'
Please Guide me why its happened?.
Thanks!
It might help if you post the exact code that causes. My guess would be that while you are using NSMutableDictionary, the call to valueForKey: returns to you a non-mutable NSArray, and you think it is returning you an NSMutableArray instance. Note that mutable arrays and dictionaries allow you to manipulate the collection of items inside them, but do not guarantee you that those items themselves are mutable. For example, if you check the Property List Programming Guide: Reading and Writing Property-List Data, you will notice the following example:
If you load the property list with
this call:
NSMutableArray * ma = [NSMutableArray arrayWithContentsOfFile:xmlFile];
ma is a mutable array with immutable
dictionaries in each element. Each key
and each value in each dictionary are
immutable.
If you need explicit control over the mutability of the objects at each level, use propertyListFromData:mutabilityOption:format:errorDescription:
You can also create an explicit NSMutableArray copy from the NSArray you got from the NSMutableDictionary.
you said you are retrieving the array as a NSArray and not casting it to a NSMutableArray before you attempt to remove an object for it. This causes an error since you can't remove an object from an NSArray
Suppose [something dictionaryValue] returns an immutable dictionary, and you want a mutable version of that dictionary. It is not enough to say:
NSMutableDictionary *d = [something dictionaryValue];
This merely tells the compiler that d is an NSMutableDictionary, but really it's the same immutable dictionary you got from [something dictionaryValue]. Instead, you need to create a new, mutable copy of the dictionary:
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:
[something dictionaryValue]];
Similarly, use [NSMutableArray arrayWithArray:...] for arrays.

how are these NSMutableArray initializations different?

In a branch of my code, I previously used this
NSMutableArray *array1 = [[NSMutableArray alloc] init];
The above array is used populate a UITableVew.
Just cause, I switched to the following:
NSMutableArray *array1 = [NSMutableArray arrayWithCapacity:0]
I made no other changes to my code) and my app crashes whenever I try to scroll down the list in the UITableView.
It looks like my array is not initialized correctly. Can someone explain why this would happen? Are the two methods not identical wrt how the underlying memory space is allocated?
Your second line of code is not retaining the NSArray, which is causing a crash. You'll need to call [array1 retain] after you call arrayWithCapacity:.
There's quite a bit of useful information in this post: Understanding reference counting with Cocoa / Objective C
In general, if you're calling a class method that doesn't start with "new" or "init" (e.g. arrayWithCapacity), you can usually assume that the returned object will be autoreleased.

Resetting NSMutableArray

What is the best a quickest way to reset an NSMutableArray?
-[NSMutableArray removeAllObjects] doesn't work for you?
removeAllObjects
removeAllObjects if assuming by 'reset', you mean you just want to empty the array.
If you are attempting to do what I think you are attempting to do, which is to keep an array empty but not release it, or at least to make it available next time it is needed then firstly you need to set a variable or a property within your class for this variable:
NSMutableArray *mutableArray;
Next add this code before the position at which you will need the empty array:
if (!mutableArray) {
mutableArray = [[NSMutableArray alloc] init];
}
Now you can safely call
[mutableArray removeAllObjects];
without fear that the array will become unavailable once empty.