В чем разница между ivars и свойствами в Objective-C


какова семантическая разница между этими 3 способами использования ivars и свойств в objective-c?

1.

@class MyOtherObject; 
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;

2.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
    @property (nonatomic, retain) MyOtherObject *otherObj;

3.

    #import "MyOtherObject.h"
    @interface MyObject {
        MyOtherObject *otherObj;
    }
2 80

2 ответа:

номер 1 отличается от двух других путем прямого объявления класса MyOtherObject, чтобы свести к минимуму количество кода, видимого компилятором и компоновщиком, а также потенциально избежать циклических ссылок. Если вы делаете это таким образом, не забудьте поместить #import в .m-файл.

объявив @свойство, (и соответствие @синтезировать в .M) файл, Вы автоматически генерируете методы доступа с семантикой памяти, обрабатываемой так, как вы указываете. Эмпирическое правило для большинства объектов Сохранить, но NSStrings, например, должны использовать Copy. В то время как синглтоны и делегаты обычно должны использовать Assign. Рукописные аксессоры утомительны и подвержены ошибкам, поэтому это экономит много печатающих и тупых ошибок.

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

self.otherObj = someOtherNewObject; // set it  
MyOtherObject *thingee = self.otherObj; // get it 

вместо обычного способа передачи сообщений:

[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it 

за кулисами вы действительно вызываете метод, который выглядит так это:

- (void) setOtherObj:(MyOtherObject *)anOtherObject {

    if (otherObject == anOtherObject) {
        return;  
    }

    MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
    otherObject = [anOtherObject retain]; // put the new value in  
    [oldOtherObject release]; // let go of the old object
} // set it

...или

- (MyOtherObject *) otherObject {  
    return otherObject;
} // get it

полная боль в заднице, верно. Теперь сделайте это для каждый Ивар в классе. Если вы не сделаете это точно правильно, вы получите утечку памяти. Лучше всего просто позволить компилятору сделать работу.

Я вижу номер 1 не имеет Ивара. Предполагая, что это не опечатка, это нормально, потому что директивы @property / @synthesize также объявят ivar для вас, за кулисами. Я верю это новое для Mac OS X-Snow Leopard и iOS4.

число 3 не имеет эти методы доступа генерируются, так что вы должны написать их самостоятельно. Если вы хотите, чтобы ваши методы доступа имели побочные эффекты, вы выполняете свой стандартный танец управления памятью, как показано выше, а затем выполняете любую побочную работу, которая вам нужна, внутри метода доступа. Если вы синтезируете свойство а также написать свой собственный, потом код версия приоритет.

Я все?

в старые времена у вас были ivars, и если вы хотели позволить какому-то другому классу установить или прочитать их, вам нужно было определить геттер (т. е. -(NSString *)foo) и сеттер (т. е. -(void)setFoo:(NSString *)aFoo;).

какие свойства дают вам сеттер и геттер бесплатно (почти!) вместе с Иваром. Поэтому, когда вы определяете свойство сейчас, вы можете установить атомарность (например, вы хотите разрешить несколько действий настройки из нескольких потоков), а также назначить/сохранить / скопировать семантику (т. е. должны сеттер копирует новое значение или просто сохраняет текущее значение - важно, если другой класс пытается установить свойство string с изменяемой строкой, которая может быть изменена позже).

это @synthesize делает. Многие люди оставляют имя ivar одинаковым, но вы можете изменить его, когда пишете свой оператор synthesize (т. е. @synthesize foo=_foo; означает сделать Ивар с именем _foo свойства foo, так что если вы хотите прочитать или написать это свойство, и вы не используете self.foo, вы нужно использовать _foo = ... - это просто поможет вам поймать прямые ссылки на ivar, если вы хотите только пройти через сеттер и геттер).

начиная с Xcode 4.6, вам не нужно использовать @synthesize оператор-компилятор сделает это автоматически и по умолчанию добавит имя Ивара с _.