问题 IOS的多重继承


我想创建一个可以从两个自定义类继承的类。 你有什么想法吗? 请看下面我的例子:

头等舱:

@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
{
    ..
}

我想创建一个可缩放和可拖动的自定义视图。 你有什么想法吗? (没有复制代码..)

我认为类似协议,但我想要基类的默认值? 我如何使用协议或类似协议来实现这一点。

谢谢你的回复!


3115
2018-05-14 16:47


起源

Objective-c不支持多重继承,您可能会找到最佳的协议解决方案。 - Daniel Larsson
我该如何实现呢?我不希望属性是委托..并且我想要默认值,例如在zoomable视图中我想要默认的小尺寸,如果子类没有覆盖函数,则返回类(50,50)。 - Rebecca
没有为协议设置默认值的真正好方法,因为它应该是未实现的。你可以做的是从一个实现协议的类继承,看看这个要点: gist.github.com/paulrehkugler/9647085 - Daniel Larsson
你懂 UIScrollView 是可拖动和可缩放的?也许你想要继承那个? - i_am_jorf
是的,我知道,谢谢,但我给这个例子了解我如何使用协议或类似的东西实现多重继承。 - Rebecca


答案:


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

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

Apple参考:

因此,在您的情况下,Composition可能是一个解决方案,下面是示例代码

@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中的所有方法,则可以在MyClass中使用Message Forwarding来处理所有方法调用。只要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

9
2018-05-18 22:38





Objective C中最接近多重继承的是类别。这些是为已存在的类添加其他方法的机制。

请注意,这有一些重要的限制:

  1. 您无法使用类别添加属性或ivars,但您可以使用 相关对象 得到类似的效果;
  2. 编译器不会告诉您是否具有在类和类别中声明的具有相同名称的方法,或者在两个类别中,因此您必须小心避免名称冲突;
  3. 这不会显示为正确的类(因为Objective C没有多重继承),因此您的代码中不会出现任何内容 ScrollableZoomableView 继承自 ScrollableView 和 ZoomableView。这在Objective C中是不可能的(例如与C ++不同)。
  4. 你需要的 -ObjC 将文件与类别链接时标记,否则你会得到 unrecognized selector 运行代码时出错;
  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

4
2018-05-17 22:11





您可能还会在objc.io中查看有关行为的这篇文章。您可以创建可拖动和可缩放的行为,然后将它们添加到您想要的任何视图中。

这是文章。


2
2018-05-22 20:27