Подтвердить что ты не робот

Переменная 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 не объявлен. Почему это так?

Спасибо.

4b9b3361

Ответ 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 всегда будет использовать свойства, более гибкие, более простые для чтения.