保留/释放问题

时间:2011-09-14 16:07:03

标签: xcode cocoa-touch memory-management retaincount

我刚刚分析了我的iPhone项目,并对XCode(4)给我的结果感到非常困惑。例如,在我的一个视图控制器中,我有以下代码:

@property (nonatomic, retain) NSArray* menuItems;
@property (nonatomic, retain) NSArray* menuItemsOptions;

- (void)viewDidLoad 
{
   [super viewDidLoad];

   self.menuItems = [[NSArray alloc] initWithObjects:
                    NSLocalizedString(@"Foo", nil), 
                    NSLocalizedString(@"Bar", nil), 
                    nil];

  [self.menuItems release];

  self.menuItemsOptions = [[NSArray alloc] initWithObjects:
                           NSLocalizedString(@"More foo", nil), 
                           NSLocalizedString(@"more bar", nil), 
                           nil];

  [self.menuItemsOptions release];
...
}

menuItems以及menuItemsOptions是具有retain选项的属性。如果我按分析,XCode将显示行[self.menuItems release];的错误:

http://i54.tinypic.com/2rqkfaf.png

为了让我更加困惑,XCode将显示行[self.menuItemsOptions release];的错误

另一种方法的类似情况:

http://i55.tinypic.com/10hof9c.png

theSelectedBegintheSelectedEnd也是带保留选项的属性。

我发布这个的原因是我的应用程序实际上会在第三方库中出现非常神秘/不易理解的回溯,除非我添加了copy在最后一张图片上看到但不要添加release。添加release或省略copy会使应用再次崩溃,这就是我决定运行分析器的原因。

我做错了什么?

3 个答案:

答案 0 :(得分:1)

尝试将someMethod更改为:

-(void) someMethod:(NSDate*)fromDate toDate:(NSDate*)toDate
{
   if (editBegin)
   {
      NSDate *copiedDate = [fromDate copy];
      self.theSelectedBegin = copiedDate;
      [copiedDate release];
   }
   else
   {
      NSDate *copiedDate = [fromDate copy];
      self.theSelectedEnd = copiedDate;
      [copiedDate release];
   }
}

如果您使用复制属性theSelectedBegin和theSelectedEnd(我推荐),例如:

@property (nonatomic, copy) NSDate *theSelectedBegin;
@property (nonatomic, copy) NSDate *theSelectedEnd;

以下代码与上述代码相同,但更简洁,更清晰。

-(void) someMethod:(NSDate*)fromDate toDate:(NSDate*)toDate
{
   if (editBegin)
   {
      self.theSelectedBegin = fromDate;
   }
   else
   {
      self.theSelectedEnd = fromDate;
   }
}

当你执行[myObj copy]时,会返回一个新对象。执行[myObj retain]会返回保留计数增加的SAME对象。如此有效,以下是BAD代码:

@property (nonatomic, copy) NSDate *myDate;
[...]

self.myDate = [someDate copy];
[self.myDate release];

打破它看起来更像......

@property (nonatomic, copy) NSDate *myDate;
[...]

NSDate *copyDate = [someDate copy];  // never gets released
self.myDate = copyDate;             // good so far for self.myDate
[self.myDate release];              // just released self.myDate (note: copyDate not released)

答案 1 :(得分:1)

您从分析器收到警告的原因是,实际上不需要getter方法返回与传入setter的对象完全相同的对象。例如,想象下面的代码:

- (void)doSomethingWithAString:(NSString *)aString {
    self.myName = [[NSString alloc] initWithFormat:@"%@ the Great", aString];
    [self.myName release];
}

使用拥有方法(-init...)创建字符串,因此您拥有它。然后你把它交给myName财产,后者取得了所有权。现在,您需要通过调用-init...来释放您从-release方法获得的所有权。大。

上述代码的问题[self.myName release]可能不会释放您传递给setter的同一对象。想象一下,如果这个setter是这样实现的:

- (void)setMyName:(NSString *)someString {
    // Make sure to trim whitespace from my name!
    NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet];
    NSString *strippedString = [someString stringByTrimmingCharactersInSet:whitespaceCharacterSet];

    [myName autorelease];
    myName = [strippedString retain];
}

请注意,传递给setter的对象存储在支持ivar中的对象。当你调用[self.myName release]时,你将释放被剥离的字符串,而不是你原来的字符串。原始字符串现已泄露,剥离的字符串已过度释放。

简而言之,绝不会假设getter返回您传递给setter的同一个对象

答案 2 :(得分:0)

属性的一个吸引人的特性是属性访问器负责保留和释放它们指向的对象。我想不出一个人会明确保留或释放财产的情况。