Chrysotribax Chrysotribax - 5 months ago 5
iOS Question

NSString : leak when assigning value to a property

Assuming we don't use ARC.
Suppose we have a very simple class in which we declare 2 NSString properties, like this :

@interface Foo : UIView {}
-(id)initWithArguments:(NSString*)mess title:(NSString*)tit;

@property(nonatomic, retain) NSString *message;
@property(nonatomic, retain) NSString *title;

and in implementation :

@implementation Foo
@synthesize message, title;

-(id)initWithArguments:(NSString*)mess title:(NSString*)tit{
if((self = [super init])){
message = mess; // (1)
self.title = tit; // (2)
return self;

message = nil;
title = nil;
[super dealloc];

Now if I call a method from another class, in which I create 2 NSString and an instance of Foo , like this :

NSString *string1 = [NSString stringWithFormat:@"some text with %d things", 5];
NSString *string2 = [NSString stringWithFormat:@"other text with %d things", 5];

Foo *foo = [[Foo alloc] initWithArguments:string1 title:string2];

The whole code works fine and doesn't crash, but, if I profile it with instruments,

  • it doesn't cause a leak when calling (1)("message = mess;")

  • it cause a leak when calling (2)("self.title = tit;")

It's very confusing, because stringWithFormat is an autoreleased object, isn't it ?
So, how an autoreleased object can cause a leak when assigning to a property ???

I read somewhere that it's almost always better to use the "self.text = value;" form instead of the "text = value;" form, because the second one may cause a leak.

Actually, in this code it's the contrary.

And... If I use a constant NSString like @"some text", instead of the values returned by [NSString stringWithFormat], there is no leak, of course.

Any idea ?


You have forgotten to invoke the (compiler-generated) setter methods in a few cases:

self.message = mess;    // in init method

self.message = nil;     // in dealloc method
self.title = nil;       // ditto

It's crucial that you use the setter/getter methods in non-ARC code.