0

我刚刚分析了我的 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

theSelectedBegin并且theSelectedEnd再次是具有保留选项的属性。

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

我究竟做错了什么?

4

3 回答 3

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]会返回一个新对象。Doing[myObj retain]返回具有增加的保留计数的 SAME 对象。如此有效,以下是糟糕的代码:

@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)
于 2011-09-14T16:48:05.677 回答
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 的相同对象

于 2011-09-14T18:29:10.340 回答
0

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

于 2011-09-14T16:29:49.773 回答