0

假设我有一个名为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];
}

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

谢谢。

4

6 回答 6

2

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

我会以此为许可进行一些不一定与您的问题直接相关的观察。

首先,如果您声明一个保留属性(如您所做的那样)并合成它,自动生成的 getter 和 setter 会为您正确处理内存管理。

如果您手动创建 setter(即使使用@synthesize现有的也可以这样做),您必须自己进行内存管理。使用任何一个特洛伊木马的例子。

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


这是一个您可以安全忽略的实现细节,但是字符串文字(例如@"blah")被编译到可执行文件中,并且无论它们被释放多少次都不会被释放。因此,对于您的示例,即使设置器没有进行正确的内存管理,也不会有泄漏。


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

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

或逻辑等价物。

您应该养成使用它的习惯,因为您需要调用超类的init方法,并且允许更改self的值,甚至可以更改为nil。

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

于 2012-07-05T15:21:51.353 回答
0

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

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

@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

}
于 2012-07-05T14:57:22.227 回答
0

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

于 2012-07-05T14:57:27.320 回答
0

synthesized setter 方法应该做正确的事情。这是它的实现示例:

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

或者:

- (void)setTestString:(NSString *)tempString
{    
    if (tempString != testString)
    {
        [testString release];
        [tempString retain];
        testString = tempString;
    }
}
于 2012-07-05T14:57:35.977 回答
0

只有在实例被破坏时才会调用 dealloc。如果你这样做:

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

在同一块中,您只需调用两次 setter。没有内存泄漏。

于 2012-07-05T14:57:43.810 回答
0

当您@synthesize在指定的属性上使用时retain,生成的设置器将正确处理多个分配的保留/释放。只要您使用self.而不是直接转到支持变量并在其中进行最终发布,dealloc就可以了。

于 2012-07-05T14:57:58.890 回答