22

Is it possible to define properties that are only available to the class they are defined in, and that class's subclasses?

Stated another way, is there a way to define protected properties?

Binarian
  • 12,296
  • 8
  • 53
  • 84
Jay Haase
  • 1,979
  • 1
  • 16
  • 36

4 Answers4

15

Technically, no. Properties are really just methods, and all methods are public. The way we "protect" methods in Objective-C is by not letting other people know about them.

Practically, yes. You can define the properties in a class extension, and still @synthesize them in your main implementation block.

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • 1
    To be "protected" the class extension interface would need to be in a separate header file to be included in the class and its subclasses. – JeremyP Nov 24 '10 at 09:37
  • As far as I can tell, any properties declared in the base classes interface extension are not available to subclasses -- they are scoped private, not protected. See this SO discussion: http://stackoverflow.com/questions/5588799/objective-c-how-do-you-access-parent-properties-from-subclasses – memmons Apr 08 '11 at 00:06
  • @Harkonian if you declare the selector yourself, you can always call it. There's no such thing as "protecting" a method other than simply hiding its declaration. Objective-C doesn't have the concept of protected or private methods. Only protected or private ivars. – Dave DeLong Apr 08 '11 at 00:14
9

This is possible by using a class extension (not category) that you include in the implementation files of both the base class and subclasses.

A class extension is defined similar to a category, but without the category name:

@interface MyClass ()

In a class extension, you can declare properties, which will be able to synthesize the backing ivars (XCode > 4.4 automatic synthesis of the ivars also works here).

In the extension class, you can override/refine properties (change readonly to readwrite etc.), and add properties and methods that will be "visible" to the implementation files (but note that the properties and methods aren't really private and can still be called by selector).

Others have proposed using a seperate header file MyClass_protected.h for this, but this can also be done in the main header file using #ifdef like this:

Example:

BaseClass.h

@interface BaseClass : NSObject

// foo is readonly for consumers of the class
@property (nonatomic, readonly) NSString *foo;

@end


#ifdef BaseClass_protected

// this is the class extension, where you define 
// the "protected" properties and methods of the class

@interface BaseClass ()

// foo is now readwrite
@property (nonatomic, readwrite) NSString *foo;

// bar is visible to implementation of subclasses
@property (nonatomic, readwrite) int bar;

-(void)baz;

@end

#endif

BaseClass.m

// this will import BaseClass.h
// with BaseClass_protected defined,
// so it will also get the protected class extension

#define BaseClass_protected
#import "BaseClass.h"

@implementation BaseClass

-(void)baz {
    self.foo = @"test";
    self.bar = 123;
}

@end

ChildClass.h

// this will import BaseClass.h without the class extension

#import "BaseClass.h"

@interface ChildClass : BaseClass

-(void)test;

@end

ChildClass.m

// this will implicitly import BaseClass.h from ChildClass.h,
// with BaseClass_protected defined,
// so it will also get the protected class extension

#define BaseClass_protected 
#import "ChildClass.h"

@implementation ChildClass

-(void)test {
    self.foo = @"test";
    self.bar = 123;

    [self baz];
}

@end

When you call #import, it basically copy-pastes the .h file to where you are importing it. If you have an #ifdef, it will only include the code inside if the #define with that name is set.

In your .h file, you don't set the define so any classes importing this .h wont see the protected class extention. In the base class and subclass .m file, you use #define before using #import so that the compiler will include the protected class extension.

d4n3
  • 1,453
  • 14
  • 13
0

You could use such syntax in subclass implementation.

@interface SuperClass (Internal)

@property (retain, nonatomic) NSString *protectedString;

@end
Arietis
  • 25
  • 8
0

You can use a category to gain your purpose

@interface SuperClass (Protected)

@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIView *topMenuView;
@property (nonatomic, strong) UIView *bottomMenuView;

@end

In Subclass, you import this category in the file .m

Chung Mai
  • 1
  • 1