objective framework entre diferencias iphone objective-c cocoa-touch

iphone - framework - objective c vs swift



¿Cómo manejar los protocolos de Objective-C que contienen propiedades? (6)

He visto que el uso de los protocolos de Objective-C se usa de una manera como la siguiente:

@protocol MyProtocol <NSObject> @required @property (readonly) NSString *title; @optional - (void) someMethod; @end

He visto este formato utilizado en lugar de escribir una superclase concreta que amplían las subclases. La pregunta es, si se ajusta a este protocolo, ¿necesita sintetizar las propiedades usted mismo? Si extiende una superclase, la respuesta es obviamente no, no es necesario. Pero, ¿cómo se manejan las propiedades que un protocolo requiere para cumplir?

A mi entender, todavía necesita declarar las variables de instancia en el archivo de encabezado de un objeto que cumpla con un protocolo que requiera estas propiedades. En ese caso, ¿podemos suponer que solo son un principio rector? Por cierto, no es el mismo caso para un método requerido. El compilador golpeará su muñeca para excluir un método requerido que enumera un protocolo. ¿Cuál es la historia detrás de las propiedades?

Aquí hay un ejemplo que genera un error de compilación (Nota: he recortado el código que no refleja el problema en cuestión):

MyProtocol.h

@protocol MyProtocol <NSObject> @required @property (nonatomic, retain) id anObject; @optional

TestProtocolsViewController.h

- (void)iDoCoolStuff; @end #import <MyProtocol.h> @interface TestProtocolsViewController : UIViewController <MyProtocol> { } @end

TestProtocolsViewController.m

#import "TestProtocolsViewController.h" @implementation TestProtocolsViewController @synthesize anObject; // anObject doesn''t exist, even though we conform to MyProtocol. - (void)dealloc { [anObject release]; //anObject doesn''t exist, even though we conform to MyProtocol. [super dealloc]; } @end


Aquí hay un ejemplo mío que funciona perfectamente, la definición de protocolo en primer lugar:

@class ExampleClass; @protocol ExampleProtocol @required // Properties @property (nonatomic, retain) ExampleClass *item; @end

A continuación se muestra un ejemplo de trabajo de una clase que admite este protocolo:

#import <UIKit/UIKit.h> #import "Protocols.h" @class ExampleClass; @interface MyObject : NSObject <ExampleProtocol> { // Property backing store ExampleClass *item; } @implementation MyObject // Synthesize properties @synthesize item; @end


Eche un vistazo a mi artículo PROPERTY IN PROTOCOL

Supongamos que tengo MyProtocol que declara una propiedad de nombre, y MyClass que se ajusta a este protocolo

Cosas que vale la pena notar

  1. La propiedad del identificador en MyClass declara y genera getter, setter y backing _identifier variable
  2. La propiedad de nombre solo declara que MyClass tiene un getter, setter en el encabezado. No genera getter, implementación setter y variable de respaldo.
  3. No puedo redeclarar esta propiedad de nombre, como ya lo declaró el protocolo. Hacer esto gritará un error

    @interface MyClass () // Class extension @property (nonatomic, strong) NSString *name; @end

Cómo usar la propiedad en el protocolo

Entonces, para usar MyClass con esa propiedad de nombre, tenemos que hacer cualquiera

  1. Declare la propiedad de nuevo (AppDelegate.h lo hace de esta manera)

    @interface MyClass : NSObject <MyProtocol> @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *identifier; @end

  2. Sintetizar nosotros mismos

    @implementation MyClass @synthesize name; @end


El protocolo simplemente le dice a todos los que saben sobre su clase a través del protocolo, que la propiedad anObject estará allí. Los protocolos no son reales, no tienen variables ni métodos en sí mismos; solo describen un conjunto específico de atributos que es verdadero acerca de su clase, de modo que los objetos que tienen referencias a ellos pueden usarlos de maneras específicas.

Eso significa que en su clase que se ajusta a su protocolo, debe hacer todo lo posible para asegurarse de que funcione un Objeto.

@property y @synthesize son en el fondo dos mecanismos que generan código para usted. @property solo dice que habrá un método getter (y / o setter) para ese nombre de propiedad. En estos días @property solo es suficiente para tener también métodos y una variable de almacenamiento creada para usted por el sistema (solía tener que agregar @sythesize ). Pero debes tener algo para acceder y almacenar la variable.


La variable, anObject, debe definirse en su definición de clase TestProtocolsViewController, el protocolo simplemente le informa que debe estar allí.

Los errores del compilador te dicen la verdad: la variable no existe. @properties son solo ayudantes después de todo.


todo lo que tienes que hacer realmente es soltar un

@synthesize title;

en su implementación y debería estar todo listo. funciona de la misma manera que simplemente poner la propiedad en su interfaz de clase.

Editar:

Es posible que desee hacer esto más específicamente:

@synthesize title = _title;

Esto coincidirá con la forma en que la síntesis automática de xcode crea propiedades y ivars si usa la auto-síntesis, de esa manera si su clase tiene propiedades de un protocolo y una clase, algunos de sus ivars no tendrán el formato diferente que podría afectar legibilidad.


Ejemplo: 2 clases (Persona y Serie) quieren usar el servicio del Visualizador ... y deben cumplir con ViewerProtocol. viewerTypeOfDescription es una propiedad obligatoria que las clases de suscriptores deben cumplir.

typedef enum ViewerTypeOfDescription { ViewerDataType_NSString, ViewerDataType_NSNumber, } ViewerTypeOfDescription; @protocol ViewerProtocol @property ViewerTypeOfDescription viewerTypeOfDescription; - (id)initConforming; - (NSString*)nameOfClass; - (id)dataRepresentation; @end @interface Viewer : NSObject + (void) printLargeDescription:(id <ViewerProtocol>)object; @end @implementation Viewer + (void) printLargeDescription:(id <ViewerProtocol>)object { NSString *data; NSString *type; switch ([object viewerTypeOfDescription]) { case ViewerDataType_NSString: { data=[object dataRepresentation]; type=@"String"; break; } case ViewerDataType_NSNumber: { data=[(NSNumber*)[object dataRepresentation] stringValue]; type=@"Number"; break; } default: { data=@""; type=@"Undefined"; break; } } printf("%s [%s(%s)]/n",[data cStringUsingEncoding:NSUTF8StringEncoding], [[object nameOfClass] cStringUsingEncoding:NSUTF8StringEncoding], [type cStringUsingEncoding:NSUTF8StringEncoding]); } @end /* A Class Person */ @interface Person : NSObject <ViewerProtocol> @property NSString *firstname; @property NSString *lastname; @end @implementation Person // >> @synthesize viewerTypeOfDescription; // << @synthesize firstname; @synthesize lastname; // >> - (id)initConforming { if (self=[super init]) { viewerTypeOfDescription=ViewerDataType_NSString; } return self; } - (NSString*)nameOfClass { return [self className]; } - (NSString*) dataRepresentation { if (firstname!=nil && lastname!=nil) { return [NSString stringWithFormat:@"%@ %@", firstname, lastname]; } else if (firstname!=nil) { return [NSString stringWithFormat:@"%@", firstname]; } return [NSString stringWithFormat:@"%@", lastname]; } // << @end /* A Class Serial */ @interface Serial : NSObject <ViewerProtocol> @property NSInteger amount; @property NSInteger factor; @end @implementation Serial // >> @synthesize viewerTypeOfDescription; // << @synthesize amount; @synthesize factor; // >> - (id)initConforming { if (self=[super init]) { amount=0; factor=0; viewerTypeOfDescription=ViewerDataType_NSNumber; } return self; } - (NSString*)nameOfClass { return [self className]; } - (NSNumber*) dataRepresentation { if (factor==0) { return [NSNumber numberWithInteger:amount]; } else if (amount==0) { return [NSNumber numberWithInteger:0]; } return [NSNumber numberWithInteger:(factor*amount)]; } // << @end int main(int argc, const char * argv[]) { @autoreleasepool { Person *duncan=[[Person alloc]initConforming]; duncan.firstname=@"Duncan"; duncan.lastname=@"Smith"; [Viewer printLargeDescription:duncan]; Serial *x890tyu=[[Serial alloc]initConforming]; x890tyu.amount=1564; [Viewer printLargeDescription:x890tyu]; NSObject *anobject=[[NSObject alloc]init]; //[Viewer printLargeDescription:anobject]; //<< compilator claim an issue the object does not conform to protocol } return 0; }

Otro ejemplo con herencia de protocolo sobre subclassing

typedef enum { LogerDataType_null, LogerDataType_int, LogerDataType_string, } LogerDataType; @protocol LogerProtocol @property size_t numberOfDataItems; @property LogerDataType dataType; @property void** data; @end @interface Loger : NSObject + (void) print:(id<LogerProtocol>)object; @end @implementation Loger + (void) print:(id<LogerProtocol>)object { if ([object numberOfDataItems]==0) return; void **data=[object data]; for (size_t i=0; i<[object numberOfDataItems]; i++) { switch ([object dataType]) { case LogerDataType_int: { printf("%d/n",(int)data[i]); break; } case LogerDataType_string: { printf("%s/n",(char*)data[i]); break; } default: break; } } } @end // A Master Class @interface ArrayOfItems : NSObject <LogerProtocol> @end @implementation ArrayOfItems @synthesize dataType; @synthesize numberOfDataItems; @synthesize data; - (id)init { if (self=[super init]) { dataType=LogerDataType_null; numberOfDataItems=0; } return self; } @end // A SubClass @interface ArrayOfInts : ArrayOfItems @end @implementation ArrayOfInts - (id)init { if (self=[super init]) { self.dataType=LogerDataType_int; } return self; } @end // An other SubClass @interface ArrayOfStrings : ArrayOfItems @end @implementation ArrayOfStrings - (id)init { if (self=[super init]) { self.dataType=LogerDataType_string; } return self; } @end int main(int argc, const char * argv[]) { @autoreleasepool { ArrayOfInts *arr=[[ArrayOfInts alloc]init]; arr.data=(void*[]){(int*)14,(int*)25,(int*)74}; arr.numberOfDataItems=3; [Loger print:arr]; ArrayOfStrings *arrstr=[[ArrayOfStrings alloc]init]; arrstr.data=(void*[]){(char*)"string1",(char*)"string2"}; arrstr.numberOfDataItems=2; [Loger print:arrstr]; } return 0; }