2012-01-27 15 views
8

Encontré este código en ShareKit, y no entiendo lo que el escritor tenía en mente, usando self en un método de clase. Hay una advertencia: Tipos de punteros incompatibles que envían 'Clase' al tipo de parámetro id<FBSessionDelegate>. Quiero limpiar estas advertencias, así puedo ver las que pueden doler más tarde. ¿Qué puedo/debería hacer que no rompa esto?Usando el método de self-class

Esto es es el SHKFacebook.m archivo y el nombre de la clase es SHKFacebook

+ (void)logout 
{ 
    FBSession *fbSession; 

    if(!SHKFacebookUseSessionProxy){ 
     fbSession = [FBSession sessionForApplication:SHKFacebookKey 
               secret:SHKFacebookSecret 
               delegate:self]; 

    }else { 
     fbSession = [FBSession sessionForApplication:SHKFacebookKey 
             getSessionProxy:SHKFacebookSessionProxyURL 
               delegate:self]; 
    } 

    [fbSession logout]; 
} 

Respuesta

13

self pueden usarse en un método de clase como una instancia de clase polimórfico.

por lo tanto, el método de la clase new puede ser implementado como esto:

+ (id)new 
{ 
    return [[self alloc] init]; 
} 

y devolvería el tipo correcto para la instancia de clase que se envió un mensaje:

ex a:

NSArray * a = [NSArray new]; // << a is an NSArray 

ex b:

NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray 

ver nota a continuación.

Entonces, lo que realmente tiene que hacer es asegurarse de que solo hay métodos de instancia en el protocolo, y que los métodos (propios) de clase se planean para adoptar los métodos de instancia en el protocolo.

En cuanto al diseño ... bueno, digamos que no lo habría escrito de esta manera. Un singleton habría sido más claro y más correcto, pero ni siquiera me gustan los singleton, así que no habría tomado esa ruta.

La advertencia se produce porque el Clase instancia (lo que se pasa) no adopte la @protocol especificado por el parámetro delegate. La instancia Class no es una instancia de la clase. Una declaración de protocolo realmente se aplica a las instancias de la clase. Por ejemplo, si adopta NSLocking, ¿el compilador espera que también implemente métodos de clase para cada método de instancia declarado en el protocolo? Respuesta: Nunca. La implementación con la que está tratando es IMO, uno de esos casos en los que es un mal uso del lenguaje, pero funciona.

aclarar la terminología:

El "Class ejemplo" es self en un método de clase:

"instancia de la clase"
+ (void)foo { self; } 

An es self en un método de instancia:

- (void)foo { self; } 

En la práctica, -[NSObject conformsToProtocol:] es +[NSObject conformsToProtocol:] y +[NSObject class] acaba de devolver self por lo que no hay errores en la ejecución.

estoy todavía no está claro, entonces, ¿por qué estoy recibiendo una advertencia, si el código cumple con los criterios que has descrito.

Los criterios que he descrito es aplicable a la ejecución , pero se aparta de la semántica del lenguaje - por lo tanto, el compilador tiene toda la razón en esto.

Para una solución al problema: No hay manera de decirle al compilador "Mi instancia de clase se ajusta a protocolo" porque la declaración de adopción se aplica a instancias de la clase.

tiene dos opciones principales:

  1. El enfoque correcto limpia: utilizar una instancia de la clase y poner en práctica el protocolo como se define.

  2. o Typecast la instancia de clase al protocolo:

    Identificación del delegado = (id) auto; fbSession = [FBSession sessionForApplication: SHKFacebookKey getSessionProxy: SHKFacebookSessionProxyURL delegado: delegado];

Si elige # 2, que puede ayudar a definir los métodos de instancia del protocolo a utilizar métodos de clase, así:

+ (void)protocolMethod { /* do stuff */ } 
- (void)protocolMethod { [self.class protocolMethod]; } 

que también implicaría que no será necesario casos. Ayudaría porque agregará advertencias si el protocolo cambiará. Estas advertencias aparecerían en los métodos de clase cuando sigas la convención.

Para reducir el ruido, también puede considerar la creación de un método para reducir el encasillado a un sólo lugar:

+ (id<SomeProtocol>)sharedSomeProtocolDelegate 
{ 
    return (id<SomeProtocol>)self; 
} 

- (id<SomeProtocol>)sharedSomeProtocolDelegate 
{ 
    return [[self class] sharedSomeProtocolDelegate]; 
} 

a continuación, puedes escribir:

fbSession = [FBSession sessionForApplication:SHKFacebookKey 
          getSessionProxy:SHKFacebookSessionProxyURL 
            delegate:[self sharedSomeProtocolDelegate]]; 

(tenga en cuenta que las implementaciones de estos tipos son en realidad grupos de clase, y verá algo diferente en el depurador o si se imprimen)

+0

Tu edición deja claro. El protocolo sólo contiene los métodos de instancia y ninguno de ellos se refiere al receptor, por cierto. Todavía no estoy claro, entonces, ¿por qué estoy recibiendo una advertencia, si el código cumple con los criterios que has descrito. – Jim

+0

detalle @Jim añadió – justin

Cuestiones relacionadas