1

I have to expose a private property to sub-classes. Since there is no such thing as "protected properties" in objc AFAIK, I'm using the @protected directive to expose the corresponding ivar that's synthesised by the complier.

This method appears to work, however, I'm not sure if I'm affecting the synthesis of the property and ARC in some inadvisable way?

I'm using a weak property here to show how the compiler forced me to use __weak modifier with the @protected directive, i.e. it appears the complier is aware of the two declarations and the link between them.

Superclass .h file

@interface Superclass : NSObject
{
@protected
SCNScene * __weak _scnScene;
}

@end

Superclass .m file

@interface Superclass ()
@property (weak, nonatomic) SCNScene * scnScene;
@end

@implementation Superclass
........
@end

Subclass .m file

@implementation Subclass
    // Can use _scnScene just fine
    _scnScene = .....
@end
Sulevus
  • 669
  • 5
  • 13
  • P.S. Of course, by using the ivar (_scnScene) directly in a sub-class I'd be bypassing any setters/getters that Super might have for it, but I'm more concerned with issues with ARC, etc. – Sulevus Mar 18 '17 at 22:31
  • `@protected` does not interfere with ARC, it defines the ivars visibility. – shallowThought Mar 18 '17 at 22:58

2 Answers2

0

In the context of a class declaration, protected is the default visibility for instance variables, so your declaration has no effect. In fact, the following declaration:

@interface Superclass : NSObject
@end

would have the precisely the same effect as the declaration you posted, because the compiler automatically synthesizes any needed ivars for declared properties, unless you declare them yourself.

jlehr
  • 15,557
  • 5
  • 43
  • 45
  • Thanks for the reply.This was my expectation as well for the behaviour of private (defined in .m file) properties. – Sulevus Mar 19 '17 at 17:58
  • (posted my prev comment above before I could finish it, so finishing here) This was exactly my expectation for the behaviour of private (defined in .m file) properties as well and that's how I implemented my super and sub-classes initially. However, I was not getting access to any super setters/getters or ivars in sub-classes, so I started looking for another solution. Maybe it depends on the compiler version and it worked in previous (or newer versions). I'm using LLVM 7.1 with Xcode 7.3 and apparently it does not allow sub-classes to access super "private" properties/corresponding ivars. – Sulevus Mar 19 '17 at 18:11
  • Visibility defaults to `private` for ivars of properties declared in Objective-C class extensions. – jlehr Mar 19 '17 at 20:35
0

Yes, it'll probably work. Don't do it this way. It's very inflexible. It forces you to declare ivars in the header, it only works with ivars, and it doesn't give you any control over read/write controls (or let you create a custom getters/setters). There isn't really a good reason to use the @ access controls anymore (not since the move to non-fragile ivars, and they weren't that useful before).

A typical way to do this is with a +Protected header with a category. For example, you'd create a header file Superclass+Protected.h like this:

@interface Superclass (Protected)
@property (weak, nonatomic) SCNScene * scnScene;
@end

Then you import that into any implementation files that are allowed to access scnScene. Note that you could make this readonly if you wanted, so internally it's writable, but to protected implementations it's only readable, and to the public, it's invisible.

This is more flexible than literal "protected" because you can import this header into any other implementation where it is appropriate. So it can also be the equivalent of C++'s "friend." Obviously naming the file and providing some header comments can be helpful to let callers know if they should or shouldn't import this file.

To any complaints that this doesn't enforce access controls (not that you made any, but for anyone that does), neither does @protected. If I call valueForKeyPath:, I can access protected ivars, too. ObjC helps you create "no trespassing signs" so that callers know when they're in places they shouldn't be. It doesn't try to stop programs from accessing their own memory space. (This would be a futile goal; you can always read private variables and call private functions in any language that allows raw memory access; the point of access controls is to help callers write correct code, not stop them from doing anything.)

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks for your reply. Yes, I'm aware of the solution with two .h files, AKA Apple's UIGestureRecognizer method ;p, but just thought this could be a faster way of doing it. And I agree using @protected in this case appears to be just adding more risk. I'd personally opt for directly exposing the super class property as read-only in the .h file and use it in the sub-classes this way. This just feels most clean and simple solution to me. (I'll leave the question open for a few more hours to see if anyone else wants to say something and mark your answer as accepted if noone else does) – Sulevus Mar 19 '17 at 18:32