Пользовательский сеттер Objective-C

Примечание. Я не использую ARC

У меня есть UILabel со следующим свойством: @property (nonatomic, retain) UILabel *someLabel; Я пытаюсь установить собственный сеттер. Может ли следующий код вызвать утечку, поскольку @property на самом деле также вызывает retain?

- (void)setSomeLabel:(UILabel *)someLabel
{
    if (someLabel != self.someLabel) {
        [self.someLabel release];
        self.someLabel = [someLabel retain];
    }

    // some custom code here
}

person darksky    schedule 30.09.2012    source источник


Ответы (4)


Примечание: я не использую ARC

Вы действительно, действительно должны.


Ваш сеттер представляет собой бесконечный цикл. Вызов self.someLabel = ... является точным эквивалентом [self setSomeLabel:...], который вызывает цикл.

Правильный ручной сеттер выглядит так:

- (void)setSomeLabel:(UILabel *)someLabel
{
  [someLabel retain];
  [_someLabel release];
  _someLabel = someLabel;

  // some custom code here
}

Есть и другие распространенные шаблоны. Главный вопрос заключается в том, должен ли запускаться «какой-то пользовательский код», если объект сбрасывается до того же значения. Если нет, то этот шаблон имеет больше смысла:

- (void)setSomeLabel:(UILabel *)someLabel
{
  if (someLabel != _someLabel) {
    [_someLabel release];
    _someLabel = [someLabel retain];

    // some custom code here
  }
}
person Rob Napier    schedule 30.09.2012
comment
в вашем первом примере кода не должно ли _someLabel = label; быть _someLabel = someLabel; вместо этого? - person AlexChaffee; 14.04.2013
comment
Эта перетасовка с сохранением/выпуском по-прежнему необходима в рамках ARC? И есть ли еще какая-то магия, которую синтезированный сеттер может делать (например, со всеми различными модификаторами, такими как strong и nonatomic и так далее), которую мы должны были бы имитировать? - person AlexChaffee; 14.04.2013
comment
Исправлена ​​опечатка. Нет, retain и release под ARC не нужны (на самом деле они незаконны). Вы можете просто нормально назначить ivar внутри сеттера. Модификатор свойства (сильный/слабый) будет применяться к ivar автоматически, если один из методов доступа не является пользовательским (если оба являются пользовательскими, вы должны объявить ivar самостоятельно). неатомный просто означает, что не нужно делать атомарные вещи. Я бы никогда не рекомендовал точно воссоздавать atomic; лучше использовать средства доступа на основе очередей (см. stackoverflow.com/questions/15934036/) - person Rob Napier; 15.04.2013

Этот код приведет ваше приложение к бесконечному циклу, так как использование self.someLabel вызывает метод setSomeLabel:.

Вы можете попробовать приведенный ниже код для своего пользовательского установщика:

 @synthesize someLabel = _someLabel;
 - (void)setSomeLabel:(UILabel *)someLabel
 {
      if (someLabel != _someLabel)
      {
           [_someLabel release];
           _someLabel = [someLabel retain];
      }

      // custom code
 }

 - (void)dealloc
 { 
     [_someLabel release];
     // ... other releases
     [super dealloc];
 }
person Nekto    schedule 30.09.2012

Нет, это совершенно нормально, поскольку вы используете здесь собственный сеттер.

@Property просто эквивалентно объявлению методов доступа.

@Synthesize будет генерировать методы доступа на основе атрибутов объявления свойства, ТОЛЬКО ЕСЛИ установщик и/или получатель НЕ РЕАЛИЗОВАНЫ.

person Shashikanth    schedule 30.09.2012
comment
@InsertWittyName, что ты имеешь в виду? Хотя Шашикант не уловил бесконечный цикл в коде ОП, его утверждения о свойстве и синтезе верны. Между объявлением свойства и прямым объявлением методов доступа есть очень тонкая разница, но она очень редко бывает важной. - person Rob Napier; 01.10.2012
comment
@RobNapier Извините, я был немного «краток» в своем комментарии, и этого не должно было быть. Я действительно думаю, что объяснения свойств и синтеза могли бы быть немного более ясными (однако они описаны правильно). - person InsertWittyName; 01.10.2012
comment
Голосование за, чтобы противодействовать нелепым голосам против. В подавляющем большинстве контекстов этот ответ правильный, за исключением отсутствия использования точечного синтаксиса в установщике. - person Carl Veazey; 01.10.2012

Я предполагаю, что вы не используете ARC...

Вы правы в том, что вы чрезмерно сохраняете переданный someLabel, а вызов освобождения свойства не очень хорош!

Я бы использовал переменную экземпляра вместо свойства:

- (void)setSomeLabel:(UILabel *)someLabel
{
    if (someLabel != _someLabel) {
        [_someLabel release];
        _someLabel = [someLabel retain];
    }

    // some custom code here
}
person InsertWittyName    schedule 30.09.2012
comment
Там нет переудержания, просто бесконечная рекурсия. (отложив в сторону педантичный момент, что бесконечная рекурсия будет сохраняться бесконечно, но исправление рекурсии фиксирует сохранение). - person Carl Veazey; 01.10.2012