сохранить / выпустить проблемы - PullRequest
0 голосов
/ 14 сентября 2011

Я только что проанализировал свой проект 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 снова вызовет сбой приложения, поэтому я решил запустить анализатор.

Что я делаю не так?

Ответы [ 3 ]

1 голос
/ 14 сентября 2011

Попробуйте изменить 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];
   }
}

Если вы используете copy для свойств 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] возвращает тот же объект с увеличенным счетом хранения. Таким образом, следующий код является плохим:

@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 голос
/ 14 сентября 2011

Причина, по которой вы получаете предупреждение от анализатора, заключается в том, что метод геттера не обязан фактически возвращать тот же объект, который вы передали в установщик.Например, представьте следующий код:

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

Строка создается методом владения (-init...), поэтому вы владеете ею.Затем вы передали его в собственность myName, которая вступила во владение.Теперь вам нужно освободить владение, которое вы получили от метода -init..., что можно сделать, вызвав -release.Отлично.

Проблема с кодом выше состоит в том, что [self.myName release] может не выпустить тот же объект, который вы передали в установщик.Представьте, что установщик был реализован следующим образом:

- (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];
}

Обратите внимание, что объект, который вы передали в установщик, - это , а не объект, который был сохранен в резервном иваре.Когда вы звоните [self.myName release], вы освобождаете очищенную строку, а не исходную строку.Исходная строка теперь была пропущена, а удаленная строка перевыпущена.

Короче говоря, никогда не предполагает, что получатель возвращает тот же объект, который вы передали установщику .

0 голосов
/ 14 сентября 2011

Одной из привлекательных особенностей свойств является то, что средства доступа к свойствам заботятся о сохранении и освобождении объектов, на которые они указывают. Я не могу вспомнить случай, когда можно было бы явно сохранить или освободить свойство.

...