Какова видимость переменных экземпляра @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
, тогда он также получит свойства (естественно), но также ли он наследует видимость переменных экземпляра?
Какая разница, если я поместил свойство в расширение класса? Это скроет свойство из подклассов, и я угадаю также переменную экземпляра. Является ли это документированным где угодно?
Ответы
Ответ 1
Синтезированный ivar полностью невидим для всего кода, который не может видеть строку @synthesize
(что в основном означает что-либо вне файла .m). Это не @protected
, это не @private
, это просто неизвестно. С помощью @private
ivar другой код, пытающийся получить к нему доступ, будет проинформирован о том, что он частный, но с синтезированным ivar, другим кодом, пытающимся получить к нему доступ, будет сказано, что этого поля просто не существует.
Как мысленный эксперимент, попробуйте представить себе ситуацию, в которой ивар действовал как @protected
. Вы делаете подкласс, и вы гадаете с иваром. Теперь вернитесь к суперклассу и измените @synthesize myProp
на @synthesize myProp=foo
. Что происходит в подклассе? Когда компилятор обрабатывает подкласс, он не может видеть строку @synthesize
, поэтому не имеет понятия, что вы просто изменили имя ivar. На самом деле, он даже не может сказать, поддерживается ли это свойство ivar вообще, или если оно реализовано с помощью специальных методов доступа. Я надеюсь, что это понятно, почему это означает, что подкласс не может получить доступ к ivar, и ни один другой класс не может быть.
Тем не менее, я не совсем уверен, что делает компилятор, если вы пишете код в том же файле .m, который пытается получить доступ к ivar. Я ожидаю, что он будет рассматривать ivar как @private
(поскольку на самом деле компилятор может видеть, что существует ivar).
Кроме того, ничто из этого не влияет на методы выполнения. Другие классы по-прежнему могут использовать методы run-c obj-c, чтобы динамически искать ваш список ivar класса и гадать с ним.
Ответ 2
Если он объявлен в вашем интерфейсе, он практически общедоступен при использовании декларации @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
Ответ 3
Синтезированная переменная действует как объявленная @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
Клянусь, я видел это в документах, но я не могу найти его прямо сейчас. Будет обновлен, если я его отслеживаю.
Ответ 4
Вы можете создать динамическое свойство и указать его компилятору, что его экземпляр будет выполняться во время выполнения.
И затем в вашем подклассе напишите свой собственный getter или синтезируйте свойство.
@interface BaseClass: NSObject
@property (неатомный, сильный) NSString * ThisWillBeSynthesizedInRespectiveSubclasses;
@end
@implementation BaseClass
@dynamic ThisWillBeSynthesizedInRespectiveSubclasses;
@end
В подклассах
@interface Подкласс: BaseClass
@end
@implementation Подкласс
@synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;
@end
или вы пишете свои собственные методы setter/getter.
Надеюсь, это поможет!
Ответ 5
Другие классы имеют доступ ко всему, что они #include
. Другими словами, ко всему, что находится внутри вашего заголовка.
Если что-то появляется только в вашем файле реализации, другие классы (включая подклассы) не знают, что он существует. Синтетическое свойство похоже на это. Другие классы знают только об этом свойстве (свойство означает метод getter и setter), но они ничего не знают о внутренней реализации его методов.
Обратите внимание, что спецификаторы доступа (public/private/protected) в obj-c являются лишь подсказкой для компилятора, даже если что-то появляется в файле заголовка, к нему нельзя получить доступ. Время выполнения не проверяет его каким-либо образом.
Что произойдет, если вы поместите его в расширение класса? Обратите внимание, что свойство представляет собой набор из двух методов. Вы просто скрываете методы из каждого класса, который включает в себя основной заголовок вашего класса, но не заголовок расширения класса.
Мы используем это, например, для объявления свойства как readonly и в продолжении класса мы объявляем его как readwrite. Затем мы можем использовать установщик только изнутри класса.