iOS的多重继承

10
我希望创建一个类,可以从两个自定义类中继承。 请问你有什么想法吗? 以下是我的示例代码:

第一个类:

@interface UIZoomableView : UIView
{
    UITapGestureRecognizer *_tapGestureRecognizer;
}

实现:

- (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;
    }];
}

第二等级:

@interface UIDraggableView : UIView

    UIPanGestureRecognizer *_panGestureRecognizer;

@end

实现:

- (void)handlePan:(UIPanGestureRecognizer*)sender
{
    ..
}

我想创建一个自定义视图,可以进行缩放和拖动。请问您有什么实现方法吗?(不要复制代码...)

我认为可以使用协议之类的东西,但我想要基类的默认值怎么办?如何使用协议或类似协议的东西来实现这一点。

感谢您的任何回复!


6
Objective-C不支持多重继承,你可能会发现最好的解决方案是使用协议(protocols)。 - Daniel Larsson
设置协议的默认值并不是一件很好的事情,因为它应该是未实现的。你可以继承一个实现了该协议的类,参考这个代码片段:https://gist.github.com/paulrehkugler/9647085 - Daniel Larsson
1
你知道UIScrollView是可拖动和缩放的吗?也许你想要继承它? - i_am_jorf
为什么你不想要一个委托?使用委托(现在使用块)是一种成熟的设计模式,比多重继承更好用。整个思路是避免子类化,而不是通过使用多重继承使其变得更加复杂。另一个优点是编译器支持它。对于多重继承,答案是“不能有这个,并且我们不抱歉”。 - gnasher729
你可以查看这个方法http://whackylabs.com/rants/?p=3,使用消息转发...正如作者所说: “更多信息请查阅苹果的文档,它是一篇很棒的文章。” - Bisca
显示剩余2条评论
2个回答

9

Objective-C不支持多重继承。您可以使用协议、组合和消息转发来实现相同的结果。

协议定义了对象必须实现的一组方法(也可以有可选方法)。组合基本上是将对另一个对象的引用包含在内,并在需要其功能时调用该对象。消息转发是一种机制,允许对象将消息传递到其他对象,例如通过组合包括的对象。

苹果参考资料:

因此,在您的情况下,组合可能是一种解决方案,以下是示例代码

@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

如果您不想在MyClass中实现ClassA和ClassB的所有方法,可以使用消息转发来处理所有方法调用。只要ClassA和ClassB没有共同的方法,下面的方法就可以正常工作。
@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

4
在Objective C中,最接近多继承的方法是使用分类(categories)。它们是一种向已存在的类添加额外方法的机制。
需要注意的是,这种方法有一些重要的限制:
  1. 你不能使用分类添加属性或实例变量,但是你可以使用关联对象来达到类似的效果;
  2. 编译器不会告诉你是否有相同名称的方法在类和分类中声明,或者在两个分类中声明,因此你必须小心避免名称冲突;
  3. 这不会出现作为一个适当的类(因为Objective C没有多重继承),所以你不会在你的代码中看到一个叫做ScrollableZoomableView的东西,它继承自ScrollableViewZoomableView。这在Objective C中是不可能的(与C++不同)。
  4. 链接带有分类的文件时,需要使用-ObjC标志,否则在运行代码时会出现未识别的选择器错误;
  5. 你不能在-init+initialize期间调用你的代码,因为它们属于基类。你需要显式初始化你的属性。你仍然可以使用+load
  6. 你也不能拦截dealloc,因此你可能需要小心地显式取消注册你的监听器。
您想要这样的东西:
@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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接