简体   繁体   中英

Access ivar from subclass in Objective-C

I have class A which has this declaration in it's .m file:

@implementation A {
    NSObject *trickyObject;
}

And class B which has this declaration in it's .h file:

@interface B : A
@end

Is there any possibility to access the trickyObject from a method declared in the class B ?

If you have a property or method that is private, but you want to make accessible to subclasses, you can put the declaration in a category .

So consider A :

//  A.h

@import Foundation;

@interface A : NSObject

// no properties exposed

@end

And

//  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

Then consider this category:

//  A+Protected.h

@interface A (Protected)

@property (readonly, nonatomic) NSInteger hiddenValue;

@end

Note, this extension doesn't synthesize the hiddenValue (the private extension in A does that). But this provides a mechanism for anyone who imports A+Protected.h to have access to this property. Now, in this example, while hiddenValue is really readwrite (as defined in the private extension within A ), this category is exposing only the getter. (You obviously could omit readonly if you wanted it to expose both the getter and the setter, but I use this for illustrative purposes.)

Anyway, B can now do things like:

//  B.h

#import "A.h"

@interface B : A

- (void)experiment;

// but again, no properties exposed

@end

And

//  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

Now A isn't exposing hiddenValue , but any code that uses this A (Protected) category (in this case, just B ) can now access this property.

And so now you can call B methods that might be using the hiddenValue from A , while never exposing it in the public interfaces.

//  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

If you're interested in a real-world example of this, consider UIKit's:

@import UIKit.UIGestureRecognizerSubclass;

Generally the state of a UIGestureRecognizer is readonly , but this UIGestureRecognizer (UIGestureRecognizerProtected) category exposes the readwrite accessors for state (to be used, as the name suggests, by gesture recognizer subclasses only).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM