В чем разница между 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 ответов


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

объявив свойство@, (и сопоставляя @synthesize в .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 = ... - это просто поможет вам поймать прямые ссылки на Ивар, если вы хотите только пройти через сеттер и геттер).

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