В чем разница между 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-файл.
объявив @свойство, (и соответствие @синтезировать в .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
оператор-компилятор сделает это автоматически и по умолчанию добавит имя Ивара с_
.