Reputation: 1683
I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
@interface AbstractClass : UIView
@property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
@end
…
@protocol ButtonDelegate
@required
- (void) buttonWasPressed;
@end
…
@interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
@implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Upvotes: 5
Views: 5797
Reputation: 22972
Do like UIGestureRecognizer
does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h
.
Only import this in the *.m
-files. Never include it in any public header.
All private properties and methods goes into *.m
-files. Use the @interface ClassName ()
Example https://gist.github.com/hfossli/8041396
Upvotes: 5
Reputation: 4510
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
@property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's @synthesize
, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
@interface Abstract ()
@property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
@end
@implementation Abstract
@synthsize buttonDelegate;
@end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without @synthsize into all subclasses:
@interface MySubclass : Abstract
@property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
@end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of @synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
Upvotes: 1
Reputation: 63707
how to my subclass can inherit some properties from its superclass without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
@interface Animal : NSObject
{
@protected
NSString *name; // default access. Only visible to subclasses.
}
@end
@implementation Animal
-(NSString*)description {
return name;
}
@end
@interface Cow : Animal
@end
@implementation Cow
-(id)init {
self=[super init];
if (self){
name = @"cow";
}
return self;
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
Cow *cow = [Cow new];
NSLog(@"%@", cow); // prints the name through internal access
// error accessing from the outside: NSLog(@"%@", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(@"%@", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those properties
Which one is it?
Upvotes: 4
Reputation: 2823
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.
Upvotes: 0
Reputation: 14128
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
@interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
@end
I am not sure about this, but give a try.
Upvotes: 1
Reputation: 20410
Create an empty category on top of your implementation file (.m):
@interface AbstractClass()
@property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
@end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
Upvotes: 1