从 Objective-C 中的子类访问 ivar
Access ivar from subclass in Objective-C
我有 class A
在它的 .m
文件中有这个声明:
@implementation A {
NSObject *trickyObject;
}
和 class B
在其 .h
文件中有此声明:
@interface B : A
@end
是否有可能从 class B
中声明的方法访问 trickyObject
?
如果您有一个 属性 或方法是私有的,但您想让子类可以访问它,您可以将声明放在 category.
中
所以考虑 A
:
// A.h
@import Foundation;
@interface A : NSObject
// no properties exposed
@end
和
// A.m
#import "A.h"
// private extension to synthesize this property
@interface A ()
@property (nonatomic) NSInteger hiddenValue;
@end
// the implementation might initialize this property
@implementation A
- (id)init {
self = [super init];
if (self) {
_hiddenValue = 42;
}
return self;
}
@end
然后考虑这个类别:
// A+Protected.h
@interface A (Protected)
@property (readonly, nonatomic) NSInteger hiddenValue;
@end
请注意,此扩展不会合成 hiddenValue
(A
中的私有扩展会合成)。但这为任何导入 A+Protected.h
的人提供了一种机制来访问此 属性。现在,在此示例中,虽然 hiddenValue
实际上是 readwrite
(如 A
中的私有扩展中所定义),但此类别仅公开 getter。 (如果你想让它同时暴露 getter 和 setter,你显然可以省略 readonly
,但我将其用于说明目的。)
无论如何,B
现在可以执行以下操作:
// B.h
#import "A.h"
@interface B : A
- (void)experiment;
// but again, no properties exposed
@end
和
// B.m
#import "B.h"
#import "A+Protected.h"
@implementation B
// but with this category, B now has read access to this `hiddenValue`
- (void)experiment {
NSLog(@"%ld", (long)self.hiddenValue);
}
@end
现在 A
不公开 hiddenValue
,但任何使用此 A (Protected)
类别的代码(在本例中,只是 B
)现在都可以访问此 属性.
因此,现在您可以调用 B
可能使用 A
中的 hiddenValue
的方法,同时永远不会在 public 接口中公开它。
// ViewController.m
#import "ViewController.h"
#import "B.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
B *b = [[B alloc] init];
[b experiment]; // this calls `B`’s exposed method, and that method is using the property not exposed by `A.h`
}
@end
如果您对此的真实示例感兴趣,请考虑 UIKit 的:
@import UIKit.UIGestureRecognizerSubclass;
通常 UIGestureRecognizer
的 state
是 readonly
,但是这个 UIGestureRecognizer (UIGestureRecognizerProtected)
类别公开了 state
的 readwrite
访问器(以顾名思义,仅供手势识别器子类使用。
我有 class A
在它的 .m
文件中有这个声明:
@implementation A {
NSObject *trickyObject;
}
和 class B
在其 .h
文件中有此声明:
@interface B : A
@end
是否有可能从 class B
中声明的方法访问 trickyObject
?
如果您有一个 属性 或方法是私有的,但您想让子类可以访问它,您可以将声明放在 category.
中所以考虑 A
:
// A.h
@import Foundation;
@interface A : NSObject
// no properties exposed
@end
和
// A.m
#import "A.h"
// private extension to synthesize this property
@interface A ()
@property (nonatomic) NSInteger hiddenValue;
@end
// the implementation might initialize this property
@implementation A
- (id)init {
self = [super init];
if (self) {
_hiddenValue = 42;
}
return self;
}
@end
然后考虑这个类别:
// A+Protected.h
@interface A (Protected)
@property (readonly, nonatomic) NSInteger hiddenValue;
@end
请注意,此扩展不会合成 hiddenValue
(A
中的私有扩展会合成)。但这为任何导入 A+Protected.h
的人提供了一种机制来访问此 属性。现在,在此示例中,虽然 hiddenValue
实际上是 readwrite
(如 A
中的私有扩展中所定义),但此类别仅公开 getter。 (如果你想让它同时暴露 getter 和 setter,你显然可以省略 readonly
,但我将其用于说明目的。)
无论如何,B
现在可以执行以下操作:
// B.h
#import "A.h"
@interface B : A
- (void)experiment;
// but again, no properties exposed
@end
和
// B.m
#import "B.h"
#import "A+Protected.h"
@implementation B
// but with this category, B now has read access to this `hiddenValue`
- (void)experiment {
NSLog(@"%ld", (long)self.hiddenValue);
}
@end
现在 A
不公开 hiddenValue
,但任何使用此 A (Protected)
类别的代码(在本例中,只是 B
)现在都可以访问此 属性.
因此,现在您可以调用 B
可能使用 A
中的 hiddenValue
的方法,同时永远不会在 public 接口中公开它。
// ViewController.m
#import "ViewController.h"
#import "B.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
B *b = [[B alloc] init];
[b experiment]; // this calls `B`’s exposed method, and that method is using the property not exposed by `A.h`
}
@end
如果您对此的真实示例感兴趣,请考虑 UIKit 的:
@import UIKit.UIGestureRecognizerSubclass;
通常 UIGestureRecognizer
的 state
是 readonly
,但是这个 UIGestureRecognizer (UIGestureRecognizerProtected)
类别公开了 state
的 readwrite
访问器(以顾名思义,仅供手势识别器子类使用。