Objective-C: How do you access parent properties from subclasses?

42,668

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.

Share:
42,668

Related videos on Youtube

memmons
Author by

memmons

Founder of App Apps, LLC. Creator of Audiotorium Notes for iPad &amp; VideoBot.

Updated on January 15, 2020

Comments

  • memmons
    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
      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
    memmons about 13 years
    Following 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
    memmons about 13 years
    Tried 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
    memmons about 13 years
    You 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
    Rog about 13 years
    Good point! You can declare your iVars as private with @private. More details here stackoverflow.com/questions/844658/…
  • memmons
    memmons about 13 years
    Thanks 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
    memmons about 13 years
    This SO discussion has some additional pertinent information: stackoverflow.com/questions/1338434/…
  • justin
    justin about 13 years
    that 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
    memmons about 13 years
    Another SO discussion with relevance: stackoverflow.com/questions/4264263/…
  • Rog
    Rog about 13 years
    Aside 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
    Rog about 13 years
    The 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/Objective‌​C/Chapters/ocPropert‌​ies.html#//apple_ref‌​/doc/uid/TP30001163-‌​CH17-SW19
  • justin
    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
    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
    memmons about 13 years
    Sherm -- 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
    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
    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
    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
    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
    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
    olivaresF over 12 years
    Well, this sucks. Why does ObjC not do it the way @Answerbot is saying?
  • Nida
    Nida almost 12 years
    this 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
    Nir Golan over 11 years
    That seems like the best answer to me, not the one originally accepted .