Go Back   MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Aug 26, 2008, 08:00 AM   #1
Mac Me Up
macrumors regular
 
Join Date: Jun 2005
Location: Australia
NSMutableArray not mutable?!

Ok, so I'm relatively new to Objective-C, but not to programming. I have set up an NSMutableArray to hold a collection of objects, that I want to add and remove from. So in my interface:
Code:
NSMutableArray *savedLocations;
if I try to add or remove objects from this array I get an exception:
"mutating method sent to immutable object"

I can get around this by copying the array adding my object, and then assigning the pointer to the new object, but this just seems silly.
Code:
NSMutableArray *test = [savedLocations mutableCopy];
[test addObject:location];
self.savedLocations = test;
[test release];
I figure I must be doing something rather stupid. Can someone give me any pointers about this?
Mac Me Up is offline   0 Reply With Quote
Old Aug 26, 2008, 08:09 AM   #2
robbieduncan
Moderator
 
robbieduncan's Avatar
 
Join Date: Jul 2002
Location: London
Please post the code that actually matters: where does something get assigned to savedLocations? Most likely you are really ending up with a NSArray, not an NSMutableArray...
robbieduncan is offline   0 Reply With Quote
Old Aug 26, 2008, 08:26 AM   #3
Mac Me Up
Thread Starter
macrumors regular
 
Join Date: Jun 2005
Location: Australia
The code is simply:
Code:
[savedLocations addObject:myLocation];
Mac Me Up is offline   0 Reply With Quote
Old Aug 26, 2008, 08:31 AM   #4
robbieduncan
Moderator
 
robbieduncan's Avatar
 
Join Date: Jul 2002
Location: London
No, that is where you try and use the array. I am asking you where you either create an array object or get an array object from elsewhere. Sounds like you are doing this:

Code:
NSMutableArray *savedLocations;
[savedLocations addObject:someObject];
This will never work: you have not created an array. You have reserved space for a pointer to an array, but it's not pointing at one.

You need to either use an alloc/init pair, a convenience constructor or otherwise get an array.

If this is what you are doing it represents a fundamental lack of understanding of what you are doing and you should stop writing code and go back to the beginning and read the language documentation...
robbieduncan is offline   0 Reply With Quote
Old Aug 26, 2008, 09:05 AM   #5
Mac Me Up
Thread Starter
macrumors regular
 
Join Date: Jun 2005
Location: Australia
Ok...I think maybe I'm not being specific enough. I am doing this in my init method:
Code:
savedLocations = [[NSMutableArray alloc] init];
then I am trying to do this in another method:
Code:
-(void)saveLocation:(SavedLocation *)location{
	[savedLocations addObject:[location retain]];
}
When I call that method I get an error. If I restructure that method to look like this:
Code:
-(void)saveLocation:(SavedLocation *)location{
	NSMutableArray *temp = [savedLocations mutableCopy];
	[temp addObject:location];
	
	self.savedLocations = temp;
	[temp release];
}
The error goes away.

This class I am doing all this in is a Singleton, but I wouldn't think that this would make any difference?
Mac Me Up is offline   0 Reply With Quote
Old Aug 26, 2008, 09:20 AM   #6
robbieduncan
Moderator
 
robbieduncan's Avatar
 
Join Date: Jul 2002
Location: London
Hmm, your initialisation is correct. As the error you are getting is a run-time not compile-time error (right) you must be assigning a non-mutable NSArray to that variable at some point. You'll need to go over your code till you find it.

I would also note that
Code:
[savedLocations addObject:[location retain]];
will leak memory: you don't need the retain as addObject will retain whatever you pass to it.
robbieduncan is offline   0 Reply With Quote
Old Aug 26, 2008, 09:31 AM   #7
Mac Me Up
Thread Starter
macrumors regular
 
Join Date: Jun 2005
Location: Australia
Thanks for your help. I commented out all my code for that class and started again. Now it works fine. Thanks for the tip on the retain as well, I had been wondering about that actually. As a JAVA dev all this release retain stuff is tedious, but the rules do seem fairly simply (release what you alloc, etc) I just wasn't quite sure how it works with arrays. Might have to do some more reading I think
Mac Me Up is offline   0 Reply With Quote
Old Aug 26, 2008, 09:37 AM   #8
robbieduncan
Moderator
 
robbieduncan's Avatar
 
Join Date: Jul 2002
Location: London
Quote:
Originally Posted by Mac Me Up View Post
but the rules do seem fairly simply (release what you alloc, etc) I just wasn't quite sure how it works with arrays. Might have to do some more reading I think
The rules are simply. You already have most of them !

If you create an object via alloc/init or copy you must release it. An object you get via any other means (convenience constructors like [NSArray array] or returned from a method call etc) should be assumed to be autoreleased unless otherwise noted.

This also goes for objects you pass to other objects: if the other object wants to keep the passed object around it will retain it. So in practical terms anything you pass to NSMutableArray via addObject: or to a NSMutableArray via setObject:forKey: for example will be retained: you should pass autoreleased objects to them.
robbieduncan is offline   0 Reply With Quote
Old Aug 26, 2008, 11:26 PM   #9
Mac Me Up
Thread Starter
macrumors regular
 
Join Date: Jun 2005
Location: Australia
Ok so my last dumb questions, is there any cases where I need to deallocate NSStrings?

Eg:
Code:
NSString *temp = @"sdfsdfsdfds";
Code:
NSString *temp2 = [otherString stringByAppendingString:@"appendMe"];
etc?

My assumption is no, but maybe I'm wrong?
Mac Me Up is offline   0 Reply With Quote
Old Aug 26, 2008, 11:45 PM   #10
ayasin
macrumors 6502
 
Join Date: Jun 2008
Here's a rule of thumb that might help you. If the name of the selector you called starts with init you need to call release. If it doesn't then it's autoreleased for you. Conversely if the selector didn't start with init and you want to keep it around you need to call retain.
__________________
iNeedStuff Shopping Assistant - MacLife called it "the ultimate iPhone grocery list maker".
Follow me on Twitter
Need a developer? PM me.
ayasin is offline   0 Reply With Quote
Old Aug 27, 2008, 12:07 AM   #11
davedelong
macrumors member
 
Join Date: Sep 2007
Location: Right here.
Send a message via AIM to davedelong
Quote:
Originally Posted by ayasin View Post
Here's a rule of thumb that might help you. If the name of the selector you called starts with init you need to call release. If it doesn't then it's autoreleased for you. Conversely if the selector didn't start with init and you want to keep it around you need to call retain.
-copy and -mutableCopy are NOT autoreleased, nor is NSArray's -componentsJoinedByString, nor is a straight up +new. I've run up against all of these in the past 24 hours.

Edit: IIRC, strings declared literally using @"" are internally a subclass of NSString called NSConstantString and are cleaned up automatically for you, since they're constant. Interesting side note:
Code:
NSString * string1 = @"Hi";
NSString * string2 = @"Hi";
NSLog(@"%x %x", *string1, *string2);
The compiler will recognized that they're the same string and only create one instance of NSConstantString. Comparing the pointers will show that they're equivalent and identical. The NSLog above will print the same memory address for both string1 and string2, indicating that they both point to the same instance of NSConstantString.

Dave

Last edited by davedelong; Aug 27, 2008 at 12:14 AM.
davedelong is offline   0 Reply With Quote
Old Aug 27, 2008, 12:14 AM   #12
kainjow
Moderator emeritus
 
kainjow's Avatar
 
Join Date: Jun 2000
Quote:
Originally Posted by davedelong View Post
-copy and -mutableCopy are NOT autoreleased, nor is NSArray's -componentsJoinedByString
What are you basing that on?
kainjow is offline   0 Reply With Quote
Old Aug 27, 2008, 12:16 AM   #13
davedelong
macrumors member
 
Join Date: Sep 2007
Location: Right here.
Send a message via AIM to davedelong
Quote:
Originally Posted by kainjow View Post
What are you basing that on?
I got a string back from it, tried releasing it, and crashed my app when it came time to pop my NSAutoreleasePool.

EDIT: WHOOPS, I meant to say it IS autoreleased when I was expect it to not be. LOL I feel dumb now.
davedelong is offline   0 Reply With Quote
Old Aug 27, 2008, 06:25 PM   #14
ayasin
macrumors 6502
 
Join Date: Jun 2008
Quote:
Originally Posted by davedelong View Post
I got a string back from it, tried releasing it, and crashed my app when it came time to pop my NSAutoreleasePool.

EDIT: WHOOPS, I meant to say it IS autoreleased when I was expect it to not be. LOL I feel dumb now.
True, copy and mutableCopy not autoreleased, thanks for the correction (although a rule of thumb doesn't have to cover every case...just the general case ). On what basis did you expect componentsJoinedByString to not be autoreleased?
__________________
iNeedStuff Shopping Assistant - MacLife called it "the ultimate iPhone grocery list maker".
Follow me on Twitter
Need a developer? PM me.
ayasin is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
nsmutablearray tacotester1 iPhone/iPad Programming 6 Apr 10, 2014 05:18 PM
NSMutableArray always replacing last value. DavidBlack Mac Programming 16 Dec 15, 2013 04:49 PM
Objective-C help with NSMutableArray dancks Mac Programming 4 Apr 15, 2013 05:25 PM
NSArray to NSMutableArray larswik Mac Programming 3 Feb 19, 2013 11:10 PM
What is the difference between NSArray and NSMutableArray anandkumar45 iPhone Tips, Help and Troubleshooting 1 Nov 2, 2012 06:09 AM

Forum Jump

All times are GMT -5. The time now is 09:37 PM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC