Каква е видимостта на @synthesized променливи на екземпляр?

Ако имате свойство във вашия публичен интерфейс като следното

@interface MyClass : NSObject
@property(strong) NSString *myProp;
@end

И след това го синтезирайте, като на практика синтезирате променливата:

@implementation MyClass
@synthesize myProp = _myProp; // or just leave it at the default name..
@end

Каква е видимостта на променливата на екземпляра _myProp? Тоест това счита ли се за @public, @protected или @private? Предполагам, че тъй като MySubClass може да наследи от MyClass, тогава ще получи и свойствата (естествено), но ще наследи ли и видимостта на променливата на екземпляра?

Каква е разликата, ако поставя свойството в разширение на клас? Това би скрило свойството от подкласове и предполагам, че променливата на екземпляра също. Това документирано ли е някъде?


person jbrennan    schedule 14.12.2011    source източник


Отговори (5)


Синтезираният ivar е напълно невидим за целия код, който не може да види реда @synthesize (което всъщност означава всичко извън .m файла). Не е @protected, не е @private, просто е неизвестен. С @private ivar, друг код, който се опитва да получи достъп до него, ще бъде уведомен, че е частен, но със синтезиран ivar, друг код, който се опитва да получи достъп до него, ще бъде уведомен, че полето просто не съществува.

Като мисловен експеримент, опитайте да си представите ситуация, в която ivar действа като @protected. Създаваш подклас и се заяждаш с ivar там. Сега се връщате към суперкласа и променяте @synthesize myProp на @synthesize myProp=foo. Какво се случва в подкласа? Когато компилаторът обработва подкласа, той не може да види реда @synthesize, така че няма да има представа, че току-що сте променили името на ivar. Всъщност той дори не може да разбере дали свойството изобщо е подкрепено от ivar или дали е имплементирано с персонализирани методи за достъп. Надявам се, че е очевидно защо това означава, че подкласът не може да има достъп до ivar, както и всеки друг клас.

Въпреки това не съм съвсем сигурен какво прави компилаторът, ако напишете код в същия .m файл, който се опитва да получи достъп до ivar. Очаквам, че ще третира ivar като @private (тъй като компилаторът всъщност може да види, че ivar съществува).

Освен това нищо от това няма отношение към методите по време на изпълнение. Други класове все още могат да използват методите за изпълнение на obj-c, за да търсят динамично списъка ivar на вашия клас и да се занимават с него.

person Lily Ballard    schedule 14.12.2011

Ако е деклариран във вашия интерфейс, той е практически публичен, когато използвате @property декларацията. Ако искате да използвате @property декларации и да запазите собствеността им наистина частна, трябва да създадете частна категория във вашата реализация.

MyClass.h

@interface MyClass : NSObject {
@private
    NSObject* foo;
}
@end

MyClass.m

#import "ClassWithPrivateProperty.h"

@interface MyClass ()
    @property (nonatomic,retain) NSObject* foo; 
@end

@implementation MyClass
@synthesize foo;
// class implementation...
@end
person Chris Wagner    schedule 14.12.2011
comment
Добър съвет, но не казва нищо за видимостта на самия ivar. - person Lily Ballard; 15.12.2011
comment
Вашият отговор всъщност не се отнася до видимостта на самия резервен ivar. - person jscs; 15.12.2011

Синтезирана променлива действа като декларирана @private:

@interface Garble : NSObject
@property (copy) NSString * s; 
@end
@implementation Garble
@synthesize s;
@end

@interface Bargle : Garble
@end

@implementation Bargle

- (void) useS {
    NSLog(@"%@", s);    // error: instance variable 's' is private
}

@end

Кълна се, че съм виждал това в документите, но не мога да го намеря в момента. Ще се актуализира, ако го проследя.

person jscs    schedule 14.12.2011

Можете да създадете динамично свойство и да го посочите на компилатора, че неговото създаване ще бъде по време на изпълнение.

И след това във вашия подклас напишете свой собствен гетер или синтезирайте свойството.

@interface BaseClass: NSObject

@свойство (неатомно, силно) NSString *ThisWillBeSynthesizedInRespectiveSubclasses;

@край

@implementation BaseClass

@dynamic ThisWillBeSynthesizedInRespectiveSubclasses;

@край

В подкласове

@interface Подклас: Базов клас

@край

@implementation Подклас @synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;

@край

или пишете свои собствени методи за настройка/получаване.

Надявам се това да помогне !

person SRP-Achiever    schedule 22.04.2014

Други класове имат достъп до всичко, което те #include. С други думи, към всичко, което е във вашия хедър.

Ако нещо се появи само във вашия файл за изпълнение, други класове (включително подкласове) не знаят, че съществува. Синтезирано свойство е такова. Други класове знаят само за свойството (свойство означава метод за получаване и настройка), но не знаят нищо за вътрешната реализация на неговите методи.

Обърнете внимание, че спецификаторите за достъп (public/private/protected) в obj-c са само намек за компилатора, че дори ако нещо се появи в заглавния файл, то не може да бъде достъпно. Времето за изпълнение не го проверява по никакъв начин.

Какво се случва, ако го поставите в разширение на клас? Обърнете внимание, че свойство е набор от два метода. Просто скривате методите от всеки клас, който включва основната заглавка на вашия клас, но не и заглавката на разширението на класа.

Използваме това например, за да декларираме свойство като само за четене и в продължението на класа го декларираме като readwrite. Тогава можем да използваме сетера само от вътрешността на класа.

person Sulthan    schedule 14.12.2011
comment
Вашите първи три параграфа са донякъде неточни; синтезираната променлива все още не може да бъде достъпна, дори ако е дефинирана в същия файл (вижте публикацията ми). Второ, директиви за обхват са повече от просто съвети; грешка на компилатора ще бъде резултат от опит за достъп до @private ivar. Прав си, че е възможно да се заобиколи това с функции по време на изпълнение. - person jscs; 15.12.2011
comment
Вие сте прав, може да има две реализации в един файл и след това в се държи като @private. Както и да е, първият намек защо не може да бъде достъпен е, защото не е включен. - person Sulthan; 15.12.2011