2010-12-08 9 views
5

He estado buscando información sobre la delegación de Apple y la documentación de protocolo para obtener una respuesta a esto, pero después de más de un día he decidido darme por vencida y dejarte chicos tienen una oportunidad. Tengo tres clases: HTTPManager, LoginManager y FetchManager. Que es fácil adivinar lo que estas clases hacen, pero para ser explícita ...Delegados en cascada y "Código que no hace lo que dice"

  • HTTPManager - Wraps NSURLConnection y proporciona una interfaz simple para LoginManager y FetchManager hacer peticiones HTTP con autenticación.
  • LoginManager/FetchManager - Básicamente la misma clase, pero responden a los mensajes de HTTPManager de manera diferente.

HTTPManager espera que un delegado implemente el protocolo HTTPManagerDelegate y tanto LoginManager como FetchManager lo hacen. Las clases Login y FetchManager también proporcionan un protocolo para mi delegado de aplicaciones para que los datos puedan recorrer todo el camino de regreso a la interfaz de usuario.

Dentro método de mi solicitud de delegado init:, inicializo tanto un inicio de sesión y un alcance gerente y obtener las siguientes advertencias para ambos:

warning: class 'MyAppDelegate' does not implement the 'HTTPManagerDelegate' protocol 
warning: incompatible Objective-C types assigning 'struct HTTPManager *', expected 'struct LoginManager *' 

Ninguna de las dos clases que se están inicializados se derivan de HTTPManager, pero lo hacen implementar el protocolo HTTPManagerDelegate. La línea de código que produce la advertencia anterior es:

_loginMgr = [[LoginManager alloc] initWithDelegate:self]; 

Entonces, ¿qué diablos está haciendo el método de LoginManager initWithDelegate: devuelve un HTTPManager*? No hay herencia y mis tipos de devolución son correctos, así que para mí este es un vudú oscuro que no puedo.

Aquí está el caparazón de mi aplicación. Es probable que existan errores tipográficos y pequeñas inconsistencias así me pregunta antes de asumir un problema sintáctico:

// HTTPManager.h 

@protocol HTTPManagerDelegate 
... 
@end 

@interface HTTPManager : NSObject 
{ 
    id <HTTPManagerDelegate> _delegate; 
    ... 
} 

- (HTTPManager *) initWithDelegate:(id <HTTPManagerDelegate>)delegate; 
... 

@end 

// LoginManager.h 

@protocol LoginManagerDelegate 
... 
@end 

@interface LoginManager : NSObject <HTTPManagerDelegate> 
{ 
    id <LoginManagerDelegate> _delegate; 
    ... 
} 

- (LoginManager *) initWithDelegate:(id <LoginManagerDelegate>)delegate; 
... 

@end 

// MyAppDelegate.h 

@interface MyAppDelegate : NSObject <NSApplicationDelegate, LoginManagerDelegate, FetchManagerDelegate> 
{ 
    LoginManager *_loginMgr; 
    ... 
} 

... 

@end 

// MyAppDelegate.m 

... 

- (MyAppDelegate *) init 
{ 
    self = [super init]; 

    if (self) 
    { 
     // WARNING HAPPENS HERE 
     _loginMgr = [[LoginManager alloc] initWithDelegate:self]; 
     ... 
    } 

    return self; 
} 

... 

Gracias de antemano.

Respuesta

3

El problema es que tiene dos métodos con la misma firma de método -initWithDelegate: pero con tipos diferentes en sus argumentos y/o tipos de devolución. El compilador no puede manejar este caso muy bien y, en ciertos casos, también podría generar errores en el tiempo de ejecución (no en su caso porque los tipos en sus métodos no difieren en tamaño, todos son punteros).

El motivo de esto (AFAIK) es que el tiempo de ejecución no tiene acceso directo a los tipos utilizados en un método. Simplemente lee un selector (que no contiene información de tipo) y decide en función de este selector qué método utilizar. Para ayudar al tiempo de ejecución a empaquetar los argumentos del método en la pila, el compilador crea una tabla en tiempo de compilación que asigna los selectores al argumento y devuelve los tipos de valor. Esta tabla tiene solo una entrada por selector. Entonces, si existen dos métodos que tienen el mismo selector pero tipos diferentes en argumentos o valor de retorno, este sistema puede fallar.

En su caso:

-init... métodos siempre deben devolver id y no un tipo específico.

Esto resuelve el problema de los diferentes tipos de devolución.El otro problema (diferentes tipos de argumentos) es más difícil de resolver. Usted puede omitir la especificación del protocolo de su declaración de método (initWithDelegate:(id)delegate) o dar los dos métodos diferentes nombres:

- (id) initWithHttpMgrDelegate:(id <HTTPManagerDelegate>)delegate; 
- (id) initWithLoginMgrDelegate:(id <LoginManagerDelegate>)delegate; 
+2

En realidad, el compilador puede inferir el método correcto de la firma de un tipo de receptor - * si * el receptor es estáticamente mecanografiado, eso es. El problema aquí es que 'alloc' devuelve' id', por lo que el compilador no tiene información para trabajar. – Chuck

+0

Buen punto, Chuck. +1 –

+0

Gracias Ole! Eso respondió todas mis preguntas y más. –

Cuestiones relacionadas