39

I've been trying to find a workaround to declare @protected properties in Objective-C so only subclasses in the hierarchy can access them (read only, not write). I read that there is no documented way of doing this so I thought of this workaround and I wanted to ask StackOverflow's opinion about it.

Every custom class at the top of the hierarchy contains three classes, one implementation and two interfaces. Let's name them:

ClassA.h
ClassA_protected.h
ClassA.m

Then any subclass of this ClassA would be as usual:

ClassB.h
ClassB.m

First I created the interface ClassA.h where I declare a protected int variable so any subclass of ClassA can have access to it:

@interface ClassA : NSObject{
    @protected
    int _myProtectedInt;
}
@end

Next step is the workaround I was talking about. However, once you read it you will see that it is quite straight forward. I declared a second interface called ClassA_protected.h which actually works as an extension of ClassA.h and allows us to tag the property as readonly:

#import "ClassA.h"
@interface ClassA ()
@property (nonatomic , readonly) int myProtectedInt;
@end

Last step of preparing the protected hierarchy is to declare its implementation in ClassA.m where we only synthesize our property:

#import "ClassA_protected.h"
@implementation ClassA
@synthesize myProtectedInt = _ myProtectedInt;
@end

This way, every class that needs to be a subclass of ClassA.h, will import ClassA_protected.h instead. So a child like, for example ClassB.h, would be as follows:

#import "ClassA_protected.h"
@interface ClassB : ClassA
@end

And an example of accessing this property from ClassB.m's implementation:

@implementation ClassB
-(void) method {
    //edit protected variable 
    _myProtectedInt= 1;

    //normal access
    self.muProtectedInt;
}
@end
Binarian
  • 12,296
  • 8
  • 53
  • 84
Alex Salom
  • 3,074
  • 4
  • 22
  • 33
  • What if I import "ClassA_protected.h" in lets say ViewController class which is accessing only ClassB? I can still access protected property of ClassA through object of ClassB in your main class (here it is ViewController class). – Dharmesh Siddhpura Sep 29 '16 at 20:03

4 Answers4

20

Sure, that works fine. Apple uses the same approach for example in the UIGestureRecognizer class. Subclasses have to import the additional UIGestureRecognizerSubclass.h file and override the methods that are declared in that file.

Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
  • Aren't protected variables supposed to only be accessed by the class itself and its subclasses? I am still able to read the variable from other classes since your making it readonly, which I think is voiding the protected variable rules – jsetting32 Mar 10 '15 at 00:37
6

For simple "properties" just use ivar instead. That's as good as properties for all practical purposes.

Moreover, the default is already protected.

Septiadi Agus
  • 1,775
  • 3
  • 17
  • 26
  • 3
    There are some situations where properties are beneficial. e.g. KVO compliance baked in, ability to act on setting/getting of a property in a single place (custom setter/getter), the fragile base class problem, etc. – occulus Jun 25 '14 at 09:13
3

If you ask for opinion, this is mine: If one decides to mutate your

_myProtectedInt

he will probably succed anyway, because it's definitely possible with Objective-C runtime. Except this, your solution is quite OK.

Oleg Trakhman
  • 2,082
  • 1
  • 17
  • 35
0

Import the protected header in the implementation only. e.g.

ClassB.h

#import "ClassA.h"
@interface ClassB : ClassA
@end

ClassB.m

#import "ClassA_protected.h"
@implementation ClassB
@end

And in a framework the protected header should be marked project so it is not included in the public headers of the framework. Apple usually use the suffix _Internal.h for their protected methods.

For init or overriding a lazy loaded get property you would need direct access to the @proteced ivar, however for your use it would be better to redeclare the property as readwrite instead then you can take advantage of any features of the setter, atomicity for example.

malhal
  • 26,330
  • 7
  • 115
  • 133