2010-04-18 14 views
7

Tengo tres clases que implementan el mismo protocolo y tienen la misma clase principal que no implementa el protocolo. Normalmente tendría el protocolo como funciones virtuales puras en la clase principal, pero no pude encontrar una forma de Objective-C para hacerlo.Objective-C Puntero a la clase que implementa un protocolo

Quiero utilizar el polimorfismo en estas subclases declarando funciones virtuales puras en la superclase y que los niños implementen esas funciones. Sin embargo, el único método de Objective-C que he encontrado para hacer esto es que cada niño decida explícitamente implementar un protocolo, cuando lo hago de esta manera la superclase no sabe que los niños implementarán ese protocolo, por lo que hay avisos de tiempo de compilación por todo el lugar.

algunos pseudo-código si eso no tenía sentido:

@interface superclass: NSObject 
{} 

@interface child1: superclass<MyProtocol> 
{} 

@interface child2: superclass<MyProtocol> 
{} 

El consumo de estas clases:

@class child1 
@class child2 
@class superclass 

@interface SomeViewController: UIViewController 
{ 
    child1 *oneView; 
    child2 *otherView; 
    superclass *currentView; 
} 

-(void) someMethod 
{ 
    [currentView protocolFunction]; 
} 

La única manera agradable que he encontrado para hacer las funciones virtuales puras en Objective-C es un truco al poner [self doesNotRecognizeSelector:_cmd]; en la clase padre, pero no es ideal ya que causará errores de tiempo de ejecución en lugar de tiempo de compilación.

+0

Parece que el camino ObjC de métodos de pura virtual/abstracto es "clusters de clase". Puede ser algo que valga la pena investigar por ti. – nmr

Respuesta

5

que era capaz de conseguir el compilador para avisarme correctamente por lo que la propiedad superclass *currentView tener este aspecto:

@property (nonatomic, retain) superclass<MyProtocol> *currentView; 
11

Los desarrolladores de Objective-C suelen utilizar la comprobación dinámica en lugar de la verificación en tiempo de compilación en estas situaciones, ya que el lenguaje y los marcos lo soportan muy bien. Así, por ejemplo, podría escribir su método como este:

- (void)someMethod 
{ 
    // See if the object in currentView conforms to MyProtocol 
    // 
    if ([currentView conformsToProtocol:@protocol(MyProtocol)]) 
    { 
     // Cast currentView to the protocol, since we checked to make 
     // sure it conforms to it. This keeps the compiler happy. 
     // 
     [(SuperClass<MyProtocol> *) currentView protocolMethod]; 
    } 
} 
+3

Por supuesto, es más confiable usar 'respondsToSelector: @selector (protocolMethod)'. – kennytm

+2

... y es necesario si el protocolo tiene métodos opcionales. – jlehr

+0

No recomendaría utilizar información de tipo de tiempo de ejecución como esta; es muy poco probable que sea un caso genuino en el que no se conoce el tipo de objeto lo suficientemente bien en tiempo de compilación para evitar hacerlo. Los casos más comunes en los que he visto usar RTTI son redundantes con un poco de reflexión. La excepción es la implementación del código de tipo genérico en Objective-C donde, lamentablemente, estamos obligados a utilizar un mecanismo fundamentalmente menos eficiente de lo que el compilador puede generar código, simplemente porque no hay genéricos en tiempo de compilación en la especificación del lenguaje (a problema compartido con/heredado de C).También, ejecutor remoto – jheriko

1

Personalmente, me gustaría implementar el protocolo en la superclase, pero poner en práctica los métodos como éste:

- (id) myProtocolMethod { 
    NSAssert(NO, [NSString stringWithFormat:@"-[%@ %@] must be overridden", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]); 
    return nil; 
} 

De esa manera, si alguna vez se olvida de anular un método en una subclase concreta, debería ser inmediatamente obvio.

+0

Depende de si todas las subclases deben ajustarse al protocolo; no estoy seguro de lo que Winder tiene en mente allí. Pero definitivamente no estoy poniendo esas aseveraciones en mi código de producción. Prefiero solo proporcionar métodos vacíos, y tal vez registrar una advertencia. – jlehr

+0

De hecho, iba a sugerir todo lo contrario: considere la posibilidad de hacer que los métodos de protocolo sean opcionales, y haga la verificación en tiempo de ejecución, pero una vez más, realmente depende de cuál sea la intención. – jlehr

+0

Este es el comportamiento que quiero, solo con un error de compilación en lugar de uno de tiempo de ejecución. No parece que Objective-C tenga una forma de hacerlo. – Winder

3

Alternativamente, puede utilizar el siguiente

if ([unknownObject conformsToProtocol:@protocol(MyProtocol)]) 
    [unknownObject performSelector:@selector(methodInProtocol)]; 

en lugar de lo siguiente, si lo que desea es suprimir la advertencia.

if ([unknownObject conformsToProtocol:@protocol(MyProtocol)]) 
    [unknownObject methodInProtocol]; // will cause warning 

performSelector: solo funcionará si el número de argumentos es cero o uno. Se pueden lograr invocaciones más flexibles con NSInvocation.

Cuestiones relacionadas