开发者

Using self.objectname causes profiler to report a memory leak

Please help;

Header File

#import <Foundation/Foundation.h>


@interface MyClass : NSObject {

    NSMutableString * myString;

}

@property (nonatomic, retain) NSMutableString * myString;

-(id) init;
-(void) dealloc;

@end

Implementation File

#import "MyClass.h"


@implementation MyClass

@synthesize myString;

-(id) init {

    if ((self = [super init])) {
        self.myString = [[NSMutableString alloc] init];
    }

    return self;
}

-(void) dealloc {
    [super dealloc];
    [self.myString release];
}

@end

Usage

MyClass * m = [[MyClass alloc] init];
[m release];
//-- Xcode 4 profiler reports a memory leak here.

However, when the code in implementation file of the class is changed to not use the [self.myStrin开发者_如何学JAVAg .....] notation, then no memory leak is reported.

So,

    -(id) init {

           if ((self = [super init])) {
                myString = [[NSMutableString alloc] init];
            }

            return self;
        }
}

and

 -(void) dealloc {
        [super dealloc];
        [myString release];
    }

works fine. No memory leaks reported.

Any ideas - is it profiler or is it me (be nice)?


Your memory leak is not caused by using your setter. Your memory leak is caused by you not managing your memory correctly!

If you declare the following property

@property (nonatomic, retain) id value;

That means that the compiler generates methods that look something like this (highly simplified):

- (id)value {
  return value;
}

- (void)setValue:(id)aValue {
  [value autorelease];
  value = [aValue retain];
}

When you use dot-notation, self.value = obj is desugared into [self setValue:obj]. Thence, you are actually causing obj to be retained within the setter. If you initially create an owning reference to obj (by using an +alloc without a corresponding -release or -autorelease), you'll have over-retained obj, and it will never be deallocated. Hence, you need to do something like this:

id obj = [[[NSObject alloc] init] autorelease];
self.value = obj;

or

id obj = [[NSObject alloc] init];
self.value = [obj autorelease];

or

id obj = [[NSObject alloc] init];
self.value = obj;
[obj release];

Whatever you do, you need to make sure that when you assert ownership of an object (by retaining it), you also release it.


Setter methods in Objective-C equate to a reatain of the new object and release of the old object. In your case the compiler will generate a setter method for your myString property that looks something like...

- (void)setMyString:(NSMutableString*)aString {
    [myString autorelease];
    myString = [aString retain];
}

When you invoke self.myString = in your init method this translates to a call to the setter. The setter in turn retains the object you pass to it. Because you've directly alloc'd the NSString it begins life with a retain count of one, you then call the setter and the retain count becomes two.

There's two approaches to fixing the problem, the first would be to add a call to [myString autorelease] after you alloc it. Or secondly switch your init method to directly assign the ivar...

// in your init method...
myString = [[NSMutableString alloc] init];

It's a good idea to avoid setter usage in init methods, not because of retain counts but because the object as a whole is not yet fully initialized.


@property (nonatomic, RETAIN)

you are retaining my friend. You have to release the object twice then because the retain count is 2

here is what you should do in the INIT method:

NSString *str = [[NSString alloc] initWithString:@"Hello World!"];
self.myString = str;
[str release]; // dont leak

Also I do not recommend using self.someProperty in the class itself. Doing so requires 1 extra objc_msgSend() to be done to access your variable and will slow down your application.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜