objective-c protocols

objective c - Objective-C Protocol Forward Declarations



protocols (4)

Al declarar su clase en MyClass.h, debe importar todos los archivos de encabezado para su superclase, así como los protocolos que adoptó en el archivo MyClass.h. Los protocolos en Objective-c se consideran como un tipo de herencia variante.

Las declaraciones a futuro se usan generalmente en la declaración de miembros de la clase.

ObjectProperties.h

@protocol ObjectProperties <NSObject> @property (strong, nonatomic) NSString *name; @property (strong, nonatomic) NSDate *date; @property (assign, nonatomic) int64_t index; @end

ClassA.h

#import <Foundation/Foundation.h> @protocol ObjectProperties; @interface ClassA : NSObject <ObjectProperties> - (void)specialSauce; @end;

ManagedClassA.h

#import <CoreData/CoreData.h> @protocol ObjectProperties; @interface ManagedClassA : NSManagedObject <ObjectProperties> - (void)doSomething; @end;

Desde el ejemplo de código anterior, he definido un protocolo en un archivo .h para ser utilizado tanto con objetos de Datos de Núcleo como con simples objetos de vanilla. Parece que "ruido" tiene clases conformes # importa el protocolo en el encabezado; Sería más limpio reenviar declarar el protocolo e importar en el archivo de implementación como lo he mostrado anteriormente. Sin embargo, Xcode lanza una advertencia cuando lo hace de esta manera:

Cannot find protocol definition for ''ObjectProperties''

El código compila, y en su mayoría funciona. Digo sobre todo porque hay algo de funkiness con Core Data tratando de crear dinámicamente los getters / setters para la propiedad escalar, pero creo que es probablemente porque he tocado un caso extremo.

Por supuesto, el trabajo más obvio es importar el encabezado del protocolo en los encabezados de clase.

Si mi comprensión es correcta (y mi conocimiento es adquirido recientemente, y por lo tanto es completamente posible que esté equivocado), si importo el protocolo en mis encabezados de clase y realizo un cambio en el protocolo, entonces todos los archivos posteriores que importen mi las clases tendrán que ser recompiladas.

¿Cuál es la forma correcta de resolver este tipo de problema?


Como declara la conformidad con el protocolo, debe importar el encabezado que contiene el protocolo.

Esto es lo mismo que importar una superclase, en lugar de declararla hacia adelante:

@class Foo; @interface Bar : Foo // Will get error: attempting to use the forward class ''Foo'' as superclass of ''Bar'' @end;


No puede reenviar declarar una superclase o un protocolo con el que se ajuste. En esos casos, debe incluir el encabezado. Esto se debe a que (en el caso de la superclase) las variables y métodos de instancia de la superclase se vuelven parte de su clase; o (en el caso de los protocolos) los métodos del protocolo se convierten en métodos declarados en su clase, sin necesidad de declararlos explícitamente. (es decir, ahora otras personas que incluyan el encabezado de su clase verán que su clase declara esos métodos, como si los hubiera declarado usted mismo). La única forma de que eso sea posible es si ya se definieron en este ámbito, es decir, se importaron sus encabezados. .

#import <SomeClass.h> #import <SomeProtocol.h> // these two must be imported @interface MyClass : SomeClass <SomeProtocol> @end

Las declaraciones directas son útiles para las cosas que simplemente aparecen en el tipo de una variable (específicamente, una variable de puntero a objeto). Los punteros a objetos son todos del mismo tamaño y no hay diferencia entre los diferentes tipos de punteros a objetos en tiempo de ejecución (el concepto de tipo de puntero a objeto es solo una cosa de tiempo de compilación). Entonces no hay una necesidad real de saber exactamente qué hay en las clases de esos tipos. Por lo tanto, pueden ser declarados adelante.

@class SomeClass; @protocol SomeProtocol; // you can forward-declare these @interface MyClass { SomeClass *var1; id<SomeProtocol> var2; } @end


Sí, tiene razón en que todos los archivos deberán ser recompilados, pero esto es necesario. Los archivos que importan el encabezado de clase necesitan conocer los métodos asociados con el protocolo que implementa. Si oculta esa definición en el archivo .m, solo estará visible para un archivo (ya que los archivos .m nunca se importarán). No es lo mismo que las clases que declaran hacia adelante. Si reenvía declara un protocolo, debe declararlo en algún lugar que sea visible en el mismo ámbito que la declaración directa. No puedo pensar en ningún ejemplo donde esto no ocurra en el mismo archivo.

En ARC esto es un error, porque ARC necesita saber sobre la administración de memoria de los métodos declarados (¿devuelven +1 instancias, punteros internos, etc.?)