Можно ли определить свойства, доступные только для класса, в котором они определены, и подклассы класса?
С другой стороны, существует ли способ определить защищенные свойства?
Можно ли определить свойства, доступные только для класса, в котором они определены, и подклассы класса?
С другой стороны, существует ли способ определить защищенные свойства?
Технически, нет. Свойства - это действительно просто методы, и все методы являются общедоступными. Способ, которым мы "защищаем" методы в Objective-C, не позволяет другим людям узнать о них.
Практически, да. Вы можете определить свойства в расширении класса и еще @synthesize
их в основном блоке реализации.
Это возможно с помощью расширения класса (не категории), которое вы включаете в файлы реализации как базового класса, так и подклассов.
Расширение класса определено аналогично категории, но без названия категории:
@interface MyClass ()
В расширении класса вы можете объявить свойства, которые смогут синтезировать поддерживающие ivars (XCode > 4.4, автоматический синтез иваров также работает здесь).
В классе расширения вы можете переопределить/уточнить свойства (изменить readonly на readwrite и т.д.) и добавить свойства и методы, которые будут "видимы" для файлов реализации (но обратите внимание, что свойства и методы на самом деле не являются закрытый и все еще может быть вызван селектором).
Другие предложили использовать отдельный файл заголовка MyClass_protected.h для этого, но это также можно сделать в главном файле заголовка с помощью #ifdef
следующим образом:
Пример:
BaseClass.h
@interface BaseClass : NSObject
// foo is readonly for consumers of the class
@property (nonatomic, readonly) NSString *foo;
@end
#ifdef BaseClass_protected
// this is the class extension, where you define
// the "protected" properties and methods of the class
@interface BaseClass ()
// foo is now readwrite
@property (nonatomic, readwrite) NSString *foo;
// bar is visible to implementation of subclasses
@property (nonatomic, readwrite) int bar;
-(void)baz;
@end
#endif
BaseClass.m
// this will import BaseClass.h
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "BaseClass.h"
@implementation BaseClass
-(void)baz {
self.foo = @"test";
self.bar = 123;
}
@end
ChildClass.h
// this will import BaseClass.h without the class extension
#import "BaseClass.h"
@interface ChildClass : BaseClass
-(void)test;
@end
ChildClass.m
// this will implicitly import BaseClass.h from ChildClass.h,
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "ChildClass.h"
@implementation ChildClass
-(void)test {
self.foo = @"test";
self.bar = 123;
[self baz];
}
@end
Когда вы вызываете #import
, он в основном копирует файл .h туда, где вы его импортируете.
Если у вас есть #ifdef
, он будет включать только код внутри, если установлен #define
с этим именем.
В вашем файле .h вы не устанавливаете определение, чтобы любые классы импортировали этот .h, не увидите расширение защищенного класса.
В базовом классе и подклассе .m файла вы используете #define
перед использованием #import
, чтобы компилятор включил расширение защищенного класса.
Вы можете использовать такой синтаксис в реализации подкласса.
@interface SuperClass (Internal)
@property (retain, nonatomic) NSString *protectedString;
@end
Вы можете использовать категорию, чтобы достичь своей цели
@interface SuperClass (Protected)
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIView *topMenuView;
@property (nonatomic, strong) UIView *bottomMenuView;
@end
В подклассе вы импортируете эту категорию в файл .m