Objective-C: How do you access parent properties from subclasses?
Solution 1
The solution you're after is to declare the MyBaseClass private property in a class extension:
@interface MyBaseClass ()
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end
You are then free to make that declaration both in MyBaseClass and in MySubclass. This lets MySubclass know about these properties so that its code can talk about them.
If the repetition bothers you, put the class extension in a .h file of its own and import it into both .m files.
I will give an example from my own code. Here is MyDownloaderPrivateProperties.h:
@interface MyDownloader ()
@property (nonatomic, strong, readwrite) NSURLConnection* connection;
@property (nonatomic, copy, readwrite) NSURLRequest* request;
@property (nonatomic, strong, readwrite) NSMutableData* mutableReceivedData;
@end
There is no corresponding .m file and that's all that's in this file; it is, as it were, purely declarative. Now here's the start of MyDownloader.m:
#import "MyDownloader.h"
#import "MyDownloaderPrivateProperties.h"
@implementation MyDownloader
@synthesize connection=_connection;
@synthesize request=_request;
@synthesize mutableReceivedData=_mutableReceivedData;
// ...
And here's the start of its subclass MyImageDownloader.m:
#import "MyImageDownloader.h"
#import "MyDownloaderPrivateProperties.h"
Problem solved. Privacy is preserved, as these are the only classes that import MyDownloaderPrivateProperties.h so they are the only classes that know about these properties as far as the compiler is concerned (and that's all that privacy is in Objective-C). The subclass can access the private properties whose accessors are synthesized by the superclass. I believe that's what you wanted to accomplish in the first place.
Solution 2
that's how you access them. how you declare them is what's biting you:
@interface MyBaseClass : NSObject
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end
this is the normal way to declare a new objc class.
by adding the parentheses (instead of declaring the superclass - NSObject in this case), you have declared a class extension, which is probably not visible to the subclass (via inclusion).
you will probably never need to declare a root class in objc:
@interface MyBaseClass // << superclass omitted
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end
NSObject (or a subclass of, assuming you're target apple's systems) should be the base class unless you're very experienced and know what a root class is for.
class extensions are often used to 'simulate' private interfaces. by simulate, the compiler doesn't enforce this, as it would be enforced in other languages. for example, all messages are still dynamic, although the subclass may (unknowingly) override methods in your extensions, if declared with the same selector.
Solution 3
Judging by the () after your base class name, it looks like you are declaring a private interface extension within your class implementation, is this the case? If so the variable will only be accessible from within that class implementation.
Does your MyBaseClass
inherits from NSObject directly?
If so, you need to declare the someObject
property in your interface file, as in:
@interface MyBaseClass : NSObject
{
}
@property (nonatomic, retain) NSObject *someObject;
And then synthesize it like you are already doing.
Related videos on Youtube
memmons
Founder of App Apps, LLC. Creator of Audiotorium Notes for iPad & VideoBot.
Updated on January 15, 2020Comments
-
memmons over 4 years
If I have this class defined, how do I access the
someObject
property in subclasses without compiler errors?@interface MyBaseClass // someObject property not declared here because I want it to be scoped // protected. Only this class instance and subclass instances should be // able to see the someObject property. @end // This is a private interface extension...properties declared here // won't be visible to subclasses. However, I don't see any way to // declare protected properties... @interface MyBaseClass (private) @property (nonatomic, readwrite, retain) NSObject *someObject; @end
@interface MySubclass : MyBaseClass @end @implementation MySubclass - (id) init { // Try to do something with the super classes' someObject property. // Always throws compile errors. // Semantic Issue: Property 'someObject' not found // object of type 'MySubclass *' self.someObject = nil; } @end
I'm obviously not understanding how inheritance works in objective-c. Could someone enlighten me?-
Chuck Wolber over 7 years@Elise - And I have flagged your comment because, while correct, it ignores the underlying conceptual question about how property inheritance works. Correcting code errors while ignoring the conceptual question the OP is actually asking is obtuse, frustrating, and not in the least bit useful.
-
-
memmons about 13 yearsFollowing good encapsulation design, I am declaring the
someObject
property private because it should not be accessible from outside the class hierarchy. Only MyBaseClass and any subclasses of MyBaseClass should see that property. If I declare the property in the interface, aren't I making it a public property? -
memmons about 13 yearsTried that -- same error. In any case, even if this did work it woudl be very fragile. What if you have a deep hierarchy? super.super.super.super.someObject?
-
memmons about 13 yearsYou and Justin make a similar point -- and I do think that is the answer. I just need to understand how this design works when considering encapsulation. Please see my comment to Justin's answer.
-
Rog about 13 yearsGood point! You can declare your iVars as private with
@private
. More details here stackoverflow.com/questions/844658/… -
memmons about 13 yearsThanks for the reference, Rog. It definitely clears up the scope of ivars. It doesn't mention properties, though and actually confuses the issue for me. If I have an ivar declared protected, is the property that uses that ivar protected as well?
-
memmons about 13 yearsThis SO discussion has some additional pertinent information: stackoverflow.com/questions/1338434/…
-
justin about 13 yearsthat is correct. the language offers no control over method visibility - only ivars. as mentioned, dynamic dispatch also allows subclasses to override any method, whether they know it or not. it's a pain sometimes, but a limitation of the language. you can tackle it a few ways: 1) use a c++ implementation/ivar, which probably offers all the visibility features you'll want. 2) document (or include in the method name) that the method is protected 3) add support for public usage 4) move the implementation to a protected ivar
-
memmons about 13 yearsAnother SO discussion with relevance: stackoverflow.com/questions/4264263/…
-
Rog about 13 yearsAside from doing what you were doing initially (which as you know now has its limitations), I am not aware of a way for you to declare a @property as private. In this case I'd probably recommend that you generate your own setter/getter methods in the parent class instead.
-
Rog about 13 yearsThe second link is a good idea - make it readonly public and redeclared it as readwrite privately. Here's Apple's take on it - hhttp://developer.apple.com/library/Mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW19
-
justin about 13 years@Harkonian all methods are publicly visible/callable via the runtime - all a client needs is selector's name, and in some cases its signature. some people simulate access reduction by declaring methods in implementation (extensions are one example). the compiler will warn you if a selector with a matching name/sig could not be found, or if the compiler can deduce that the object may not respond to the selector. even those warnings may be stepped around and the method may be called if a client is insistent.
-
Sherm Pendley about 13 years@Harkonian - Why should one need to be forcibly restrained from breaking encapsulation? You know it's a bad idea, so just don't do it - even if the language allows it.
-
memmons about 13 yearsSherm -- I'm all for good design, but if the language doesn't support it, what option do you have? It seems I can either not use properties at all, since they don't support scoping of any sort, and use ivars instead or I can use public properties for everything that needs to be visible in subclasses and document how they should be used. Either case breaks object-oriented design principles in some way.
-
justin about 13 years@Sherm i write a bit in c++ as well as objc. it's too often that i'll attempt to break it - by accident. fortunately, the compiler checks and catches that. it's also nice to force an implementation to change, if something must be hidden. dependencies must be updated immediately in that event. programs live and are maintained by many people for many years, it's better to have a tool and language features to verify a design's correctness as programs evolve, imo.
-
Sherm Pendley about 13 years@Harkonian - What option do you have? Design your code well anyway. Just because the language doesn't force you to use good design doesn't mean it won't allow you to use it.
-
Sherm Pendley about 13 years@Justin - That's a good point, the lack of access restrictions does place a bigger burden on the programmer. With great power comes great responsibility! :-)
-
memmons about 13 years@Justin: Suggestion 1) (only use ivars, not properties) seems to be quite limiting when dealing with OOD. Suggestion 2) is an option, but oviously not ideal since accidental use of public properties that are supposed to be private could easily happen. Suggestion 3) breaks encapsulation. Suggestion 4) Changing the scope of the ivar to protected seems the best route, even if the property is still available publicly. I'll have to do a bit of research to see how scoped ivars affect public properties.
-
justin about 13 years@Harkonian re #1: the implementation and storage just moves to a c++ object. the c++ object then holds one or more ivars, declares the public interface, and is responsible for the implementation. then you just expose the interface the objc type offers by creating method wrappers. of the options i listed, it is the one i use it most... but what limitations are you concerned about?
-
olivaresF over 12 yearsWell, this sucks. Why does ObjC not do it the way @Answerbot is saying?
-
Nida almost 12 yearsthis seems like the more direct answer to the general problem of how to let subclasses access the private interface of a superclass. the repetition does bother me, though. Might just make the properties public...
-
Nir Golan over 11 yearsThat seems like the best answer to me, not the one originally accepted .