属性分配两次时避免内存泄漏

时间:2012-07-05 14:52:02

标签: iphone objective-c memory-management properties memory-leaks

假设我有一个名为 MyTestClass.h 的课程。

类结构看起来像

@interface MyTestClass : NSObject {

    NSString *testString;   
}

@property (nonatomic, retain)NSString * testString;

@end

.m文件

@implementation MyTestClass

@synthesize testString;    

-(id) init{ 

    [self setTestString:@""];           
    return self;
}

-(void)dealloc{ 

    [self.testString release];      
    testString = nil;

    [super dealloc];
}

@end

现在我创建了 MyTestClass 的对象并分配了 testString 两次

MyTestClass * myTestClass = [[MyTestClass alloc] init];

[myTestClass setTestString:@"Hi"];
[myTestClass setTestString:@"Hello"];

现在我想,我的testStrings内存被泄露了两次!! (一个通过 init(),另一个通过我的第一个 setTestString 方法)

我是对的吗?或将@property (nonatomic, retain)处理/释放以前分配的内存?

或者,在这种情况下,我需要覆盖 MyTestClass.m 中的 setTestString(),如下面的代码

-(void)setTestString:(NSString *)tempString{    

    [testString release];
    testString = nil;

   testString = [tempString retain];
}

对此问题的任何帮助表示赞赏。

感谢。

6 个答案:

答案 0 :(得分:2)

  

对此问题的任何帮助表示赞赏。

我会将此作为许可证,使得观察结果不一定与您的问题直接相关。

首先,如果你声明一个retain属性(正如你所做的那样)并对其进行综合,那么自动生成的getter和setter会为你正确处理内存管理。

如果您手动创建setter(即使存在@synthesize也允许这样做),您必须自己进行内存管理。使用trojanfoe的任何一个例子。

你问题中的setter包含一个错误,如果testString == tempString,即你将属性的值赋给自己,你最终可能会为该属性分配一个悬空指针,因为你有效地释放了tempString然后保留它


这是一个安全忽略的实现细节,但是字符串文字,例如@"blah"被编译到可执行文件中,无论它们被释放多少次都不会被释放。所以,举个例子,即使setter没有做正确的内存管理,也不会有泄漏。


顺便说一句,init方法的正常模式是

-(id) init
{
    self = [super init];
    if (self != nil)
    {
        // init stuff
    }
    return self;
}

或逻辑等价物。

你应该养成使用它的习惯,因为你需要调用超类的init方法,并允许它改变self的值,甚至是nil。

此外,虽然通常在释放后将对象引用设置为nil是非常好的做法,但在这两种情况下,都是不必要的。第一次,变量即将超出范围,第二次立即从其他对象中分配变量。

答案 1 :(得分:0)

这不是泄漏。正确处理合成变量。

以这种方式实现合成方法(对于retain关键字)

@property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;

- (void)setString:(NSString*)newString
{
    if (newString != _string) {
       [_string release];
       _string = [newString retain];
    }
}

当然这是泄密:

- (void)aMethod //of my class with string property
{
   NSString *aString = [[NSString alloc] initWithString:@"hello"];
   self.string = aString; //retain count of 2
   self.string = @"hello2"; //retain count of 1 for aString

  //now I don't release aString.... leak

}

答案 2 :(得分:0)

如果您使用自动生成的setter(在您的情况下,setTestString:,也由self.testString = ...;调用),retain属性的先前值在被设置之前被释放。所以不,您在上面发布的代码中没有泄漏。

答案 3 :(得分:0)

synthesize d setter方法应该做正确的事情。以下是它的实现示例:

- (void)setTestString:(NSString *)tempString
{    
    [tempString retain];
    [testString release];
    testString = tempString;
}

或:

- (void)setTestString:(NSString *)tempString
{    
    if (tempString != testString)
    {
        [testString release];
        [tempString retain];
        testString = tempString;
    }
}

答案 4 :(得分:0)

仅在实例被销毁时调用dealloc。 如果你这样做:

[myTestClass setTestString:@"Hi"];
[myTestClass setTestString:@"Hello"];

在同一个区块中,你是两个叫做二传手的人。没有内存泄漏。

答案 5 :(得分:0)

在指定@synthesize的属性上使用retain时,生成的setter将正确处理多个赋值的保留/释放。只要您使用self.而不是直接转到支持变量并在dealloc中进行最终发布,您应该没问题。