Поддерживает ли Objective-C трейты/примеси?

Существуют ли какие-либо методы для эмуляции трейтов или примесей в Objective-C?

В Scala, например, я могу сделать что-то вроде этого:

trait ControllerWithData {
  def loadData = ...
  def reloadData = ...
  def elementAtIndex = ...
}

trait ControllerWithStandardToolbar {
  def buildToolbar = ...
  def showToolbar = ...
  def hideToolbar = ...
}

class MyTableController extends ControllerWithData 
                        with ControllerWithStandardToolbar {
  def loadView = {
     super.loadView

     loadData
     buildBar
  }
}

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


person Bill    schedule 08.04.2011    source источник
comment
Хотите объяснить, что такое черты и примеси? Концепции могут поддерживаться, но известны под другим именем.   -  person Sherm Pendley    schedule 09.04.2011
comment
Похоже, кто-то внедрил черты Obj-C здесь: etoileos.com// новости/архив/2011/07/12/1427   -  person Bill    schedule 12.07.2011


Ответы (3)


Прямой языковой поддержки нет, но вы можете сделать что-то подобное с пересылкой сообщений. Допустим, у вас есть трейт-классы «Foo» и «Bar», которые определяют методы «-doFoo» и «-doBar» соответственно. Вы можете определить свой класс, чтобы он имел черты, например:

@interface MyClassWithTraits : NSObject {
    NSMutableArray *traits;
}
@property (retain) NSMutableArray* traits;

-(void) addTrait:(NSObject*)traitObject;
@end

@implementation MyClassWithTraits
@synthesize traits;

-(id)init {
    if (self = [super init]) {
        self.traits = [NSMutableArray array];
    }
    return self;
}

-(void) addTrait:(NSObject*)traitObject {
    [self.traits addObject:traitObject];
}

/*  Here's the meat - we can use message forwarding to re-send any messages
    that are unknown to MyClassWithTraits, if one of its trait objects does
    respond to it.
*/
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector {
    // If this is a selector we handle ourself, let super handle this
    if ([self respondsToSelector:aSelector])
        return [super methodSignatureForSelector:aSelector];

    // Look for a trait that handles it
    else
        for (NSObject *trait in self.traits)
            if ([trait respondsToSelector:aSelector])
                return [trait methodSignatureForSelector:aSelector];

    // Nothing was found
    return nil;
}

-(void) forwardInvocation:(NSInvocation*)anInvocation {
    for (NSObject *trait in self.traits) {
        if ([trait respondsToSelector:[anInvocation selector]]) {
            [anInvocation invokeWithTarget:trait];
            return;
        }
    }

    // Nothing was found, so throw an exception
    [self doesNotRecognizeSelector:[anInvocation selector]];
}
@end

Теперь вы можете создавать экземпляры MyClassWithTraits и добавлять любые объекты «признаков», которые вам нужны:

MyClassWithTraits *widget = [[MyClassWithTraits alloc] init];
[widget addTrait:[[[Foo alloc] init] autorelease]];
[widget addTrait:[[[Bar alloc] init] autorelease]];

Вы можете сделать эти вызовы -addTrait: в методе -init MyClassWithTraits, если хотите, чтобы каждый экземпляр этого класса имел одинаковые черты. Или вы можете сделать это, как я сделал здесь, что позволяет вам назначать разные наборы признаков для каждого экземпляра.

И тогда вы можете вызывать -doFoo и -doBar так, как если бы они были реализованы виджетом, даже если сообщения перенаправляются в один из его типовых объектов:

[widget doFoo];
[widget doBar];

(Изменить: добавлена ​​обработка ошибок.)

person Sherm Pendley    schedule 08.04.2011
comment
Потрясающий! когда вы увидели вопрос, вы не знали, что такое черты, и вы искали и даже реализовали это!!! Я хотел знать одну вещь, почему методSignatureForSelector нужно переопределить. недостаточно forwardInvocation? когда вызывается methodSignatureForSelector? какой поток? - person Amogh Talpallikar; 21.08.2013

Черты или миксины не поддерживаются Objective-C, у вас есть только встроенная опция категорий. Но, к счастью, в Objective-C Runtime есть почти все инструменты для реализации собственной идеи при смешивании или трейтах с добавлением методов и свойств в ваш класс во время выполнения. Подробнее о возможностях, предоставляемых средой выполнения Objective-C, можно прочитать на веб-сайте документации Apple среде выполнения Objective-C. Документы

Идея такова:

1) Вы можете создать протокол Objective-C (Mixin), в котором вы будете объявлять свойства и методы.

2) Затем вы создаете класс (реализация Mixin), который будет реализовывать методы из этого протокола.

3) Вы делаете свой некоторый класс, в котором хотите предоставить возможность композиции с миксинами, чтобы соответствовать этому протоколу (Миксину).

4) Когда ваше приложение запускается, вы добавляете с помощью среды выполнения Objective-C все реализации из класса (реализация Mixin) и свойства, объявленные в (Mixin), в ваш класс.

5) вуаля :)

Или вы можете использовать готовые проекты с открытым исходным кодом, такие как "Alchemiq"

person Aleksey Getman    schedule 30.01.2017