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:
El enfoque correcto limpia: utilizar una instancia de la clase y poner en práctica el protocolo como se define.
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)
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
detalle @Jim añadió – justin