从 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

请注意,此扩展不会合成 hiddenValueA 中的私有扩展会合成)。但这为任何导入 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;

通常 UIGestureRecognizerstatereadonly,但是这个 UIGestureRecognizer (UIGestureRecognizerProtected) 类别公开了 statereadwrite 访问器(以顾名思义,仅供手势识别器子类使用。