Переменная Property vs. instance
Я пытаюсь понять, как стратегии используют некоторые люди, чтобы отличать экземпляры vars от свойств. Общий шаблон выглядит следующим образом:
@interface MyClass : NSObject {
NSString *_myVar;
}
@property (nonatomic, retain) NSString *myVar;
@end
@implementation MyClass
@synthesize myVar = _myVar;
Теперь я подумал, что вся эта стратегия такова, что можно легко отличить разницу между ivar и свойством. Поэтому, если я хочу использовать управление памятью, унаследованное синтезированным свойством, я бы использовал что-то вроде:
myVar = @"Foo";
Другим способом будет ссылка на него через self. [ivar/property here].
Проблема с использованием стратегии @synthesize myVar = _myVar заключается в том, что я пишу код, например:
myVar = some_other_object; // doesn't work.
Компилятор жалуется, что myVar не объявлен. Почему это так?
Спасибо.
Ответы
Ответ 1
Свойства - это просто сеттеры и геттеры для ivars
и должны (почти) всегда использоваться вместо прямого доступа.
@interface APerson : NSObject {
// NSString *_name; // necessary for legacy runtime
}
@property(readwrite) NSString *name;
@end
@implementation APerson
@synthesize name; // use name = _name for legacy runtime
@end
@synthesize
создает в этом случае эти два метода (не на 100% точнее):
- (NSString *)name {
return [[_name copy] autorelease];
}
- (void)setName:(NSString *)value {
[value retain];
[_name release];
_name = value;
}
Теперь легко отличить ivars
и getters/setters. Аксессоры получили префикс self.
. В любом случае вы не должны обращаться к переменным напрямую.
Ваш пример кода не работает так, как должно быть:
_myVar = some_other_object; // _myVar is the ivar, not myVar.
self.myVar = some_other_object; // works too, uses the accessors
Ответ 2
Синтетическое свойство с именем prop
фактически представлено двумя методами prop
(возвращающим текущее значение свойства) и setProp:
(установка нового значения для prop).
Синтаксис self.prop
- синтаксический сахар для вызова одного из этих аксессуаров. В вашем примере вы можете сделать любое из следующих действий, чтобы установить свойство myVar
:
self.myVar = @"foo"; // handles retain/release as specified by your property declaration
[self setMyVar: @"foo"]; // handle retain/release
_myVar = @"Foo"; // does not release old object and does not retain the new object
Чтобы получить доступ к свойствам, используйте self.propname
. Для доступа к переменным экземпляра используйте только имя переменной экземпляра.
Ответ 3
Проблема с использованием стратегии @synthesize myVar = _myVar заключается в том, что я пишу код, например:
myVar = some_other_object; // doesn't work.
Компилятор жалуется, что myVar
не объявлен. Почему это так?
Поскольку переменная myVar
не объявлена.
Этот оператор использует синтаксис для доступа к переменной, будь то переменная экземпляра или какой-либо другой вид. Как сказал вам rincewind, чтобы получить доступ к свойству, вы должны использовать либо синтаксис доступа к свойствам (self.myVar = someOtherObject
), либо явное сообщение для метода доступа ([self setMyVar:someOtherObject]
).
В противном случае вы пытаетесь получить доступ к переменной, и поскольку у вас нет переменной с именем myVar
, вы пытаетесь получить доступ к переменной, которая не существует.
Ответ 4
В общем, я называю свои свойства такими же, как мои переменные экземпляра; это предположение по умолчанию, которое делает синтаксис @property
. Если вы обнаружите, что боретесь с настройками по умолчанию, вы делаете это неправильно (или ваш фреймворк sux, что не подходит для Cocoa/Cocoa-touch, на мой взгляд).
Ошибка компилятора, потому что использование свойств всегда должно иметь ссылку на объект, даже внутри вашей собственной реализации класса:
self.stuff = @"foo"; // property setter
[stuff release]; // instance variable
stuff = @"bar"; // instance variable
return self.stuff; // property getter
Я знаю, что многие программисты Cocoa не согласны, но я считаю, что плохая практика заключается в использовании свойств внутри вашей реализации класса. Я бы предпочел увидеть что-то вроде этого:
-(void) someActionWithStuff: (NSString*) theStuff {
// do something
[stuff release];
stuff = [theStuff copy];
// do something else
}
чем это:
-(void) someActionWithStuff: (NSString*) theStuff {
// do something
self.stuff = theStuff;
// do something else
}
Я предпочитаю делать управление памятью как можно яснее. Но даже если вы не согласны, использование формы self.stuff
подскажет любому опытному программисту Objective-C, что вы вызываете свойство, а не обращаетесь к переменной экземпляра. Это тонкий момент, который легко для начинающих замаскировать, но после того, как вы некоторое время работали с Objective-C 2.0, это довольно ясно.
Ответ 5
Дон,
В соответствии с "правилами" вы должны вызвать Release для каждой копии, Alloc и Retain. Так почему вы называете Release на вещи? Это предполагается, что он был создан с использованием Alloc, Copy или Retain?
Возникает еще один вопрос: вредно ли вызывать Release на ссылку на объект, если он уже выпущен?
Ответ 6
Так как Apple резервирует префикс для себя, и поскольку я предпочитаю сделать его более очевидным, когда я использую setter, и когда я использую ivar, я принял практическое применение префикса i_ на моих ivars, например,
@interface MyClass : NSObject {
NSString *i_myVar;
}
@property (nonatomic, retain) NSString *myVar;
@synthesize myVar = i_myVar;
i_myVar = [input retain];
self.myVar = anotherInput;
[i_myVar release]
Поскольку очень важно знать, когда вы используете setter, и когда вы используете ivar, я считаю, что явно другое имя безопаснее.
В вашем вопросе это должно быть:
self.myVar = @"Foo"; // with setter, equivalent to [self setMyVar:@"Foo"]
и
_myVar = some_other_object; // direct ivar access - no memory management!
Помните, что вы не должны использовать сеттеры/геттеры в init/dealloc, поэтому вам нужно сделать свой прямой доступ к IVAR (и осторожному управлению памятью) в этих методах.
Ответ 7
что не так просто с помощью
@interface MyClass : NSObject
@property NSString *prop;
@end
неатомические и сохранение не требуются, сохранить значение по умолчанию, а атомный/неатомный isn\t важно, если XCode не сообщает вам предупреждение.
НЕ нужно объявлять iVar, для вас будет создан имя _prop, если вы действительно хотите его использовать (я не понимаю, почему, если честно)
@synthesize НЕ требуется.
когда (и вы должны) использовать ARC, вам не нужно беспокоиться о сохранении и освобождении.
держите это просто!
Кроме того, если у вас есть такой метод, как этот
- (void)aMethod:(NSString*)string
{
self.prop = string;
// shows very clearly that we are setting the property of our object
_aName = string;
// what is _aName ? the _ is a convention, not a real visual help
}
i всегда будет использовать свойства, более гибкие, более простые для чтения.