Многократное наследование для 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
{
    ..
}

Я хочу создать настраиваемое представление, которое можно масштабировать и перетаскивать. У вас есть идея сделать это, пожалуйста? (без кода копирования..)

Я думаю что-то вроде протоколов, но мне нужно значение по умолчанию для базовых классов? Как я могу реализовать это с помощью протокола или что-то вроде протоколов.

Спасибо за любой ответ!

Ответ 1

Objective-C не поддерживает множественное наследование. Вы можете использовать протокол, состав и пересылку сообщений для достижения того же результата.

Протокол определяет набор методов, которые должен реализовывать объект (возможно также иметь необязательные методы). Композиция - это в основном метод включения ссылки на другой объект и вызов этого объекта, когда требуется его функциональность. Пересылка сообщений - это механизм, который позволяет объектам передавать сообщения на другие объекты, например объект, который включен в состав композиции.

Справочник Apple:

Итак, в вашем случае композиция может быть решением, ниже приведен пример кода

@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

Если вы не хотите внедрять все методы из ClassA и ClassB в MyClass, вы можете использовать пересылку сообщений в MyClass для обработки всех вызовов метода. Ниже работает нормально, пока 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

Ответ 2

Самое близкое, что вы можете получить к множественному наследованию в Objective C, - это категории. Это механизм добавления дополнительных методов в уже существующий класс.

Обратите внимание, что это имеет некоторые важные ограничения:

  • Вы не можете добавлять свойства или ivars с помощью категории, хотя вы можете использовать связанные объекты, чтобы получить аналогичный эффект;
  • Компилятор не скажет вам, есть ли у вас методы с тем же именем, которые объявлены в классе и категории, или в двух категориях, поэтому вы должны быть осторожны, чтобы избежать столкновения имен;
  • Это не будет выглядеть как правильный класс (поскольку Objective C не имеет множественного наследования), поэтому у вас не будет чего-то в вашем коде с именем ScrollableZoomableView, который наследует от ScrollableView и ZoomableView. Это невозможно в Objective C (в отличие от С++, например).
  • При связывании файлов с категориями вам нужен флаг -ObjC, иначе при запуске кода вы получите ошибки unrecognized selector;
  • Вы не можете получить свой код во время -init или +initialize, потому что они относятся к базовому классу. Вы должны явно инициализировать свои свойства. Вы все равно можете использовать +load, хотя:
  • Вы также не можете перехватывать 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

Ответ 3

Вы также можете посмотреть эту статью в objc.io о поведении. Вы можете создавать перетаскиваемые и масштабируемые типы поведения, а затем добавлять их во все виды, которые вы хотите.

Здесь статья.