2011-04-08 9 views
12

¿Hay alguna técnica para emular rasgos o mixins en Objective-C?¿Objective-C admite caracteres/mixins?

En Scala, por ejemplo, puedo hacer algo como esto:

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 
    } 
} 

Es básicamente una manera de combinar (o mezclar en) múltiples piezas de funcionalidad en una sola clase. Así que en este momento tengo un tipo de UIViewController de uso múltiple del que forman parte todos mis controladores, pero sería mejor si pudiera desglosarlo y que los controladores específicos heredaran un comportamiento específico.

+0

Cuidado de explicar qué rasgos y mixins son? Los conceptos pueden ser compatibles, pero se conocen por un nombre diferente. –

+0

Claro, déjame revisar. – Bill

+0

Parece que alguien ha implementado los rasgos Obj-C aquí: http://etoileos.com//news/archive/2011/07/12/1427/ – Bill

Respuesta

18

No hay compatibilidad directa con el idioma, pero puede lograr algo similar con el reenvío de mensajes. Digamos que tiene las clases de rasgos "Foo" y "Bar", que definen los métodos "-doFoo" y "-doBar", respectivamente. Se podría definir la clase de tener rasgos, como esto:

@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 

Ahora, puede crear instancias de MyClassWithTraits, y añadir lo que sea "rasgo" objetos desea:

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

que podría hacer estas llamadas al -addTrait: en el método MyClassWithTraits '-init, si desea que cada instancia de esa clase tenga el mismo tipo de rasgos. O bien, podría hacerlo como lo he hecho aquí, lo que le permite asignar un conjunto diferente de rasgos a cada instancia.

Y entonces se le puede llamar -doFoo y -doBar como si estuvieran implementados por flash, a pesar de que los mensajes están siendo enviados a uno de sus rasgos objetos:

[widget doFoo]; 
[widget doBar]; 

(Editar: gestión de errores añadido.)

+0

¡Impresionante! cuando viste la pregunta, no sabías cuáles eran los rasgos y buscaste e incluso implementaste esto !!! Quería saber una cosa, ¿por qué es necesario anular methodSignatureForSelector. ¿No hay suficiente invocación? ¿Cuándo se llama methodSignatureForSelector? cuál es el flujo? –

-4

Probablemente estés buscando categorías. Ver http://macdevelopertips.com/objective-c/objective-c-categories.html.

+1

Lamentablemente, no lo creo. Lo he considerado y creo que si hay alguna forma de hacerlo, implicará categorías. Pero las categorías te permiten mezclar métodos en una clase específica, no múltiples clases (¿no?), Así que no creo que sean suficientes. Pero podría estar equivocado. – Bill

+0

Las categorías se definen en una sola clase. Sin embargo, otras clases heredadas de esa clase también heredan las categorías. – Zr40

+4

Las categorías definitivamente no son rasgos en el sentido de Scala. Son más como clases parciales en tierra C#. –

0

Los rasgos o mixins no son compatibles con Objective-C, solo tiene la opción incorporada de Categorías. Pero, afortunadamente, Objective-C Runtime tiene casi todas las herramientas para implementar la idea propia si se mezclan o los rasgos con la adición de métodos y propiedades a su clase en tiempo de ejecución. Puede leer más sobre las oportunidades de los cuales Objective-C en tiempo de ejecución prevé que en el sitio web de documentación de Apple Objective-C Runtime Docs

La idea es:

1) Se puede crear un protocolo de Objective-C (Mixin), en el que se declarará propiedades y métodos.

2) A continuación, crea una clase (implementación de Mixin), que implementará los métodos de este protocolo.

3) Usted hace su clase, en la que desea proporcionar la posibilidad de composición con mixins, para conformar ese protocolo (Mixin).

4) Cuando se inicia su aplicación, agrega con Objective-C runtime todas las implementaciones de la clase (implementación de Mixin) y las propiedades declaradas en (Mixin) en su clase.

5) voilà :)

O puede utilizar algunos proyectos de código abierto listas como "Alchemiq"

Cuestiones relacionadas