Reputation: 653
I want create a class that can inherit from two custom class. Do you have any idea to do this please? Please see below my example:
first class:
@interface UIZoomableView : UIView
{
UITapGestureRecognizer *_tapGestureRecognizer;
}
and implementation:
- (void)onDoubleTap:(UITapGestureRecognizer *)sender
{
CGSize newSize;
CGPoint centerPoint = self.center;
if ([self isSmall])
{
newSize = [self bigSize];
}
else
{
newSize = [self smallSize];
}
[UIView animateWithDuration:0.3 animations:^{
self.size = newSize;
self.center = centerPoint;
}];
}
Second class:
@interface UIDraggableView : UIView
UIPanGestureRecognizer *_panGestureRecognizer;
@end
implementation:
- (void)handlePan:(UIPanGestureRecognizer*)sender
{
..
}
i want to create a custom view that can be zoomable and draggable. Do you have any idea to do this please? (without copy code..)
I think something like protocols but i want default value for the base classes? How can i implement this using protocol or something like protocols.
Thanks for any response!
Upvotes: 10
Views: 4066
Reputation: 832
Objective-C doesn't support multiple inheritance. You could use a protocol, composition and message forwarding to achieve the same result.
A protocol defines a set of methods that an object must implement (it's possible to have optional methods too). Composition is basically the technique of include a reference to another object and calling that object when it's functionality is required. Message forwarding is a mechanism that allows objects to pass messages onto other objects, for example, an object that is included via composition.
Apple Reference:
So, in your case Composition might be a solution, below is the example code
@interface ClassA : NSObject {
}
-(void)methodA;
@end
@interface ClassB : NSObject {
}
-(void)methodB;
@end
@interface MyClass : NSObject {
ClassA *a;
ClassB *b;
}
-(id)initWithA:(ClassA *)anA b:(ClassB *)aB;
-(void)methodA;
-(void)methodB;
@end
@implementation MyClass
-(id)initWithA:(ClassA *)anA b:(ClassB *)aB {
a = anA ;
b = aB ;
}
-(void)methodA {
[a methodA] ;
}
-(void)methodB {
[b methodB] ;
}
@end
If you don't want to implement all the methods from ClassA and ClassB in MyClass, you can use Message Forwarding in MyClass to handle all the method invocations. Below works fine as long as ClassA and ClassB do not have any common methods.
@implementation MyClass
-(id)initWithA:(ClassA *)anA b:(ClassB *)aB {
a = anA ;
b = aB ;
}
//This method will be called, when MyClass can not handle the method itself
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([a respondsToSelector:[anInvocation selector]])
[a invokeWithTarget:someOtherObject];
else if ([b respondsToSelector:[anInvocation selector]])
[b invokeWithTarget:someOtherObject];
else
[super forwardInvocation:anInvocation];
}
@end
Upvotes: 9
Reputation: 6847
The closest that you can get to multiple inheritance in Objective C is with categories. These are a mechanism for adding additional methods to a class that already exists.
Note that this has some important limitations:
ScrollableZoomableView
which inherits from ScrollableView
and ZoomableView
. That's not possible in Objective C (unlike C++ for example).-ObjC
flag when linking files with categories, otherwise you'll get unrecognized selector
errors when you run your code;-init
or +initialize
, because those belong to the base class. You'll need to initialize your properties explicitly. You can still use +load
though;You want something like this:
@interface UIView (Zoomable)
@property (nonatomic) UITapGestureRecognizer * my_tapGestureRecognizer;
@end
@implementation UIView (Zoomable)
-(void)my_enableZooming() {
self.my_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(my_onDoubleTap:)];
self.my_tapGestureRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:self.my_tapGestureRecognizer];
}
-(void)my_disableZooming() {
[self removeGestureRecognizer:self.my_tapGestureRecognizer];
self.my_tapGestureRecognizer = nil;
}
-(void)my_onDoubleTap:(UITapGestureRecognizer *)sender {
...
}
-(UITapGestureRecognizer)my_tapGestureRecognizer {
return objc_getAssociatedObject(self, @selector(my_tapGestureRecognizer));
}
-(void)setMy_tapGestureRecognizer:(UITapGestureRecognizer)value {
objc_setAssociatedObject(self, @selector(my_tapGestureRecognizer), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
@interface UIView (Draggable)
@property (nonatomic) UIPanGestureRecognizer * my_panGestureRecognizer;
@end
@implementation UIView (Draggable)
-(void)my_enableDragging() {
self.my_panGestureRecognizer = ...;
}
-(void)my_disableDragging() {
...
}
-(void)my_handlePan:(UIPanGestureRecognizer*)sender {
...
}
-(UIPanGestureRecognizer)my_panGestureRecognizer {
return objc_getAssociatedObject(self, @selector(my_panGestureRecognizer));
}
-(void)setMy_panGestureRecognizer:(UIPanGestureRecognizer)value {
objc_setAssociatedObject(self, @selector(my_panGestureRecognizer), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
Upvotes: 4