Какова видимость @synthesized переменных экземпляра? - PullRequest
16 голосов
/ 14 декабря 2011

Если у вас есть свойство в вашем публичном интерфейсе, как показано ниже

@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, тогда он также получит свойства (естественно), но будет ли он также наследовать видимость переменной экземпляра?

Какая разница, если я поместил свойство в расширение класса? Это скрыло бы свойство от подклассов, и я предполагаю, что переменная экземпляра тоже. Это где-нибудь задокументировано?

Ответы [ 5 ]

29 голосов
/ 15 декабря 2011

Синтезированный ивар совершенно невидим для всего кода, который не может видеть строку @synthesize (что в основном означает что-либо вне файла .m).Это не @protected, это не @private, это просто неизвестно.При использовании @private ivar другому коду, пытающемуся получить к нему доступ, будет сообщено, что он является закрытым, но при использовании синтезированного ivar другому коду, пытающемуся получить к нему доступ, будет сказано, что поле просто не существует.В качестве мысленного эксперимента попробуйте представить ситуацию, когда ивар действовал так, как будто он был @protected.Вы делаете подкласс, и вы бредите там с помощью ивара.Теперь вернитесь в суперкласс и измените @synthesize myProp на @synthesize myProp=foo.Что происходит в подклассе?Когда компилятор обрабатывает подкласс, он не может видеть строку @synthesize, поэтому он не будет знать, что вы просто изменили имя ivar.На самом деле, он даже не может сказать, поддерживается ли свойство иваром вообще, или реализовано ли оно с помощью пользовательских методов доступа.Я надеюсь, очевидно, почему это означает, что подкласс не может получить доступ к ivar, как и любой другой класс.

Тем не менее я не совсем уверен, что делает компилятор, если вы пишете код в том же самом.m файл, который пытается получить доступ к ivar.Я ожидаю, что он будет рассматривать ивар как @private (поскольку компилятор фактически может видеть, что ивар существует).

Кроме того, ни одно из этого не имеет никакого отношения к методам времени выполнения.Другие классы могут по-прежнему использовать методы времени выполнения obj-c для динамического поиска списка иваров вашего класса и его использования.

1 голос
/ 23 апреля 2014

Вы можете создать динамическое свойство и указать его компилятору, что его создание будет во время выполнения.

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

@interface BaseClass: NSObject

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

@ end

@ реализация BaseClass

@ dynamic ThisWillBeSynthesesclassesRec1013 *

@ end

В подклассах

@ interface Подкласс: BaseClass

@ end

@ Подкласс реализации @synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSyntcizedIn

@ end

или вы пишете свои собственные методы установки / получения.

Надеюсь, это поможет!

1 голос
/ 15 декабря 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

Клянусь, я видел это в документах , но сейчас я не могу ее найти.Будет ли обновление, если я отследить его.

1 голос
/ 14 декабря 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
0 голосов
/ 15 декабря 2011

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

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

Обратите внимание, что спецификаторы доступа (public / private / protected) в obj-c являются лишь подсказкой компилятору, что даже если что-то появляется в заголовочном файле, к нему нельзя получить доступ. Среда выполнения не проверяет это никак.

Что произойдет, если вы поместите его в расширение класса? Обратите внимание, что свойство - это набор из двух методов. Вы просто скрываете методы от каждого класса, который включает основной заголовок класса, но не заголовок расширения класса.

Мы используем это, например, для объявления свойства как доступного только для чтения, а при продолжении класса мы объявляем его как readwrite. Тогда мы можем использовать сеттер только изнутри класса.

...