Почему переименовать синтезированные свойства в iOS с ведущими подчеркиваниями?

Возможный дубликат:
Как подчеркивается символ подчеркивания перед переменной в классе cocoa objective-c?

При создании нового проекта в Xcode 4 код шаблона добавляет символ подчеркивания, когда он синтезирует ivars в файле реализации следующим образом:

@synthesize window = _window;

или

@synthesize managedObjectContext = __managedObjectContext;

Может ли кто-нибудь сказать мне, что здесь делается? Я не полный nube, но это один из аспектов objective-c Я не понимаю.

Еще одна путаница; в реализации делегирования приложения, после синтеза окна iVar, как указано выше, в приложении didFinishLaunchingWithOptions: метод окна и viewController ivars относятся к использованию self:

self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];

но в методе dealloc он _window или _viewController

Спасибо

Ответ 1

Это артефакт предыдущей версии среды выполнения Objective-C.

Первоначально @synthesize использовался для создания методов доступа, но время выполнения все еще требовало, чтобы переменные экземпляра были явно заданы:

@interface Foo : Bar {
  Baz *_qux;
}

@property (retain) Baz *qux;
@end

@implementation Foo
@synthesize qux = _qux;

- (void)dealloc {
  [_qux release];
  [super dealloc];
}

@end

Люди будут префикс своих переменных экземпляра, чтобы отличать их от своих свойств (хотя Apple не хочет, чтобы вы использовали символы подчеркивания, но это другое дело). Вы синтезируете свойство, чтобы указать на переменную экземпляра. Но дело в том, что _qux - это переменная экземпляра, а self.qux (или [self qux]) - это сообщение qux, отправленное объекту self.

Мы используем переменную экземпляра непосредственно в -dealloc; используя метод доступа, будет выглядеть так (хотя я не рекомендую его по причинам, которые я объясню вкратце):

- (void)dealloc {
  self.qux = nil; // [self setQux:nil];
  [super dealloc];
}

Это приводит к освобождению qux, а также к обнулению ссылки. Но у этого могут быть неудачные побочные эффекты:

  • Вы можете запустить несколько неожиданных уведомлений. Другие объекты могут наблюдать изменения qux, которые записываются, когда для его изменения используется метод доступа.
  • (Не все согласны в этом вопросе:) Нулевая указатель, поскольку он может скрыть логические ошибки в вашей программе. Если вы когда-либо обращались к переменной экземпляра объекта после, объект был освобожден, вы делаете что-то серьезно неправильно. Однако из-за семантики Objective-C nil -messaging вы никогда не узнаете, использовав аксессуар для установки на nil. Если бы вы выпустили переменную экземпляра напрямую и не обнуляли ссылку, доступ к удаленному объекту вызвал бы громкий EXC_BAD_ACCESS.

В более поздних версиях среды выполнения добавлена ​​возможность синтезировать переменные экземпляра в дополнение к методам доступа. В этих версиях среды выполнения приведенный выше код можно записать без исключения переменных экземпляра:

@interface Foo : Bar
@property (retain) Baz *qux;
@end

@implementation Foo
@synthesize qux = _qux;

- (void)dealloc {
  [_qux release];
  [super dealloc];
}

@end

Это фактически синтезирует переменную экземпляра на Foo, называемую _qux, к которой обращаются сообщения getter и setter -qux и -setQux:.

Я рекомендую против этого: это немного грязно, но есть одна веская причина использовать подчеркивание; а именно, для защиты от случайного прямого доступа к ivar. Если вы считаете, что можете доверять себе, помните, используете ли вы исходную переменную экземпляра или метод доступа, просто сделайте это так:

@interface Foo : Bar
@property (retain) Baz *qux;
@end

@implementation Foo
@synthesize qux;

- (void)dealloc {
  [qux release];
  [super dealloc];
}

@end

Затем, если вы хотите получить доступ к переменной экземпляра напрямую, просто скажите qux (который переводит на self->qux в синтаксис C для доступа к элементу из указателя). Если вы хотите использовать методы доступа (которые будут уведомлять наблюдателей и делать другие интересные вещи и сделать вещи более безопасными и удобными в отношении управления памятью), используйте self.qux ([self qux]) и self.qux = blah; ([self setQux:blah]).

Грустная вещь здесь заключается в том, что образец кода Apple и код шаблона отстой. Никогда не используйте его как руководство к правильному стилю Objective-C и, конечно же, никогда не используйте его в качестве руководства к правильной архитектуре программного обеспечения.:)

Ответ 2

Вот еще одна причина. Без подчеркивания переменных экземпляра вы часто получаете предупреждение с параметрами self.title = title и self.rating = rating:

@implementation ScaryBugData
@synthesize title;
@synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
    if (self = [super init]) {
        self.title = title; // Warning. Local declaration hides instance variable
        self.rating = rating; // Warning. Local declaration hides instance variable
    }
    return self;
}
@end

Вы избегаете предупреждения путем переопределения переменных экземпляра:

@implementation ScaryBugData
    @synthesize title = _title;
    @synthesize rating = _rating;
    - (id)initWithTitle:(NSString *)title rating:(float)rating {
        if (self = [super init]) {
            self.title = title; // No warning
            self.rating = rating; // No warning
        }
        return self;
    }
    @end

Ответ 3

в приложении didFinishLaunchingWithOptions: метод окна и viewController ivars относятся к использованию self

Нет, это не так. Это ссылки на свойства window и viewController. Это точка подчеркивания, чтобы сделать ее более ясной, когда свойство используется (без подчеркивания), и когда к ивару обращаются напрямую (с подчеркиванием).

Ответ 4

Да, это просто для того, чтобы отличить ссылку объекта. То есть, если объект передается напрямую, используйте его с подчеркиванием, иначе используйте self для ссылки на объект.