【问题标题】:Memory management in objective C?目标C中的内存管理?
【发布时间】:2011-08-04 10:53:40
【问题描述】:

我有两个属性 NSString,我已经合成并且都是只读的,所以我不能使用属性方法 self.但我虽然两个传递的字符串大部分都被保留了。所以,我添加了retain来保留属性。但我觉得,我会在这里泄漏,因为传递的对象增加了它们的保留计数。但是我的属性会在不发送消息的情况下保留这些字符串吗?

-(void)setValue:(NSString *)passedString1 second:(NSString *)passedString2{
     myString = [passedString1 retain];
     hisString = [passedString2 retain];
}

假设我有声明为 NSArray 的数组(变量)的属性,并且我以这种方式将 NSDictionary 作为参数传递;

NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"text", @"This is some text", nil];
[self setValueForArray:dict];

-(void)setValueForArray:(NSDictionary*)passedDict{
 NSArray *someArray = [NSArray arrayWithObject:passedDict];
 if(array!=someArray){
 [array release];
 array = someArray; //I dont think I should retain this property here since it is retained by someArray
 }
}

这种方法对于 NSDictionary 和 NSArray 类型是否正确。

【问题讨论】:

  • 你尝试过构建和分析吗?
  • 是的,我这里有一些漏洞。我认为这些泄漏是因为passedString1 和passedString2 被保留。这些字符串不是由alloc、copy或retain创建的,而是在上面的方法中保留的。
  • 您是否将属性仅声明为只读或复制或保留?
  • 我已将属性声明为保留。

标签: iphone memory-management


【解决方案1】:

对字符串使用copy 并释放前一个对象:

-(void)setValue:(NSString *)passedString1 second:(NSString *)passedString2
{
     if (myString != passedString1)
     {
         [myString release]; 
         myString = [passedString1 copy];
     }

     if (hisString != passedString2)
     {
         [hisString release];
         hisString = [passedString2 copy];
     }
}

如果需要release作为参数传入的Strings,在调用setValue:后在调用方法中进行

【讨论】:

  • 如果myString 恰好是与passedString1 相同的对象并且myString 在您调用该方法时保留计数为1,这可能会失败。首先,它将释放myString(使其保留计数为零),然后不能保证您能够复制passedString1,因为它与myString 相同,并且myString 可能已经被释放了。
【解决方案2】:

是的,如果您这样做,您的属性(更准确地说,与属性对应的实例变量)将保留传递的字符串。但是,您还必须确保在分配新值时释放以前的值。例如,

- (void)setValue:(NSString*)passedString1 second:(NSString*)passedString2 {
    if (passedString1 != myString) {
        [myString release];
        myString = [passedString1 retain];
    }
    if (passedString2 != hisString) {
        [hisString release];
        hisString = [passedString2 retain];
    }
}

另外,请确保在 dealloc 方法中释放 myStringhisString

【讨论】:

    【解决方案3】:

    如果要保留任何属性,建议将该属性声明为retain并使用self。上面的代码很容易泄漏内存,因为您在一种方法中保留了一些东西,并可能在其他地方释放它们。这会造成很多麻烦,因为这两种方法彼此相关,但在某种程度上不基于您的应用程序逻辑。 (可怕!!以后阅读代码时必须记住它。或者如果您希望其他人查看您的代码,请记录它...)

    当我希望保留某些变量但仍不想在标头中使用保留属性时,我会创建一个扩展并覆盖该属性,然后使用 self。

    MyClass.h

    @interface MyClass : NSObject
    {
        SomeClass *someObject; //Example
        ...
    }
    @property (nonatomic) SomeClass *someObject;
    ...
    @end
    

    MyClass.m

    @interface MyClass () //Category
    @property (nonatomic, retain) SomeClass *someObject;
    @end
    
    @implementation MyClass
    ...
    // Use self.someObject and the object will be retained.
    // Release that object in dealloc.
    @end
    

    编辑: NSString 与您的情况相同。只需将 retain 替换为 copy,因为它推荐用于 NSString。

    【讨论】:

    • 新场景不会改变任何东西。关键是你不能依赖 someArray 被保留在其他地方。如果您想拥有所有权,请接受它。不要指望其他任何东西来保留它。如果稍后更改该模块怎么办?如果您没有取得所有权,此代码将失效。
    猜你喜欢
    • 1970-01-01
    • 2015-09-25
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    相关资源
    最近更新 更多