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).