views:

73

answers:

2

This makes no sense to me. Maybe someone here can explain why this happens.

I've got an NSMutableString that I alloc at the top of my iPhone app, then append to later in the process. It results in a SIGABRT, which doesn't add up to me. Here's the code:

Header File (simplified):

@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    NSMutableString *locationErrorMessage;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, copy) NSMutableString *locationErrorMessage;

@end

And the relevant parts of the Main:

@implementation MyAppDelegate

@synthesize window;
@synthesize locationErrorMessage;


- (void)applicationDidFinishLaunching:(UIApplication *)application {
    self.locationErrorMessage = [[NSMutableString alloc] init];  
}

- (void)anotherFunction {
    [self.locationErrorMessage appendString: @"Blah Blah Blah"];
}

This all seems simple enough. What am I missing?

+2  A: 

I would call this a bug in how property setters are generated, but the answer is pretty simple:

You declared the property as (nonatomic, copy). This means that whenever the locationErrorMessage property is set, it's going to invoke copy on the new value and use that copy as the property value.

Unfortunately, invoking copy on an NSMutableString does not result in an NSMutableString, it results in an NSString (which cannot be mutated using something like appendString:).

So the simple fix would be to change the property declaration from copy to retain.

(I would say that the bug would be: If you declare a property for a mutable object as copy, then the copy setter should actually use mutableCopy and not copy) => rdar://8416047

Dave DeLong
Makes perfect sense -- thank you!
Axeva
+2  A: 

Your property is copying the passed in string. A copy always is immutable, so you’re trying to send appendString: to an immutable NSString. Declare your property as retain and it will work or write a custom setter that copies the string using mutableCopy.

You also have a memory leak, you should use [NSMutableString string] instead of the alloc-init sequence.

Sven