ultima tutorial objective metodos logo ejemplos caracteristicas objective-c inheritance subclass visibility declared-property

objective c - tutorial - Exponer un método o propiedad privado de Objective-C a las subclases



objective c ultima version (7)

Eso es porque ni siquiera hay una distinción real entre privado y público. Si bien el compilador puede advertirte sobre una interfaz que no tiene un determinado método o variable de instancia, tu programa seguirá funcionando.

Según una charla oficial, una clase en Objective-C solo debería exponer los métodos y las propiedades públicas en su encabezado:

@interface MyClass : NSObject @property (nonatomic, strong) MyPublicObject *publicObject; - (void)publicMethod; @end

y los métodos / propiedades privados deben mantenerse en la extensión de clase en el archivo .m:

@interface MyClass() @property (nonatomic, strong) MyPrivateObject *privateObject; - (void) privateMethod; @end

y no creo que haya un tipo protected para cosas que son privadas pero accesibles desde subclases. Me pregunto, ¿hay alguna forma de lograr esto, además de declarar las propiedades / métodos privados públicamente?


Esto es posible utilizando una extensión de clase (no categoría) que incluya en los archivos de implementación tanto de la clase base como de las subclases.

Una extensión de clase se define de forma similar a una categoría, pero sin el nombre de la categoría:

@interface MyClass ()

En una extensión de clase, puede declarar propiedades, que podrán sintetizar los ivars de respaldo (XCode> 4.4 Síntesis automática de los ivars también funciona aquí).

En la clase de extensión, puede anular / refinar las propiedades (cambiar de solo lectura a readwrite, etc.) y agregar propiedades y métodos que serán "visibles" para los archivos de implementación (pero tenga en cuenta que las propiedades y métodos no son realmente privados y pueden todavía ser llamado por el selector).

Otros han propuesto usar un archivo de encabezado separado MyClass_protected.h para esto, pero esto también se puede hacer en el archivo de cabecera principal usando #ifdef como este:

Ejemplo:

BaseClass.h

@interface BaseClass : NSObject // foo is readonly for consumers of the class @property (nonatomic, readonly) NSString *foo; @end #ifdef BaseClass_protected // this is the class extension, where you define // the "protected" properties and methods of the class @interface BaseClass () // foo is now readwrite @property (nonatomic, readwrite) NSString *foo; // bar is visible to implementation of subclasses @property (nonatomic, readwrite) int bar; -(void)baz; @end #endif

BaseClass.m

// this will import BaseClass.h // with BaseClass_protected defined, // so it will also get the protected class extension #define BaseClass_protected #import "BaseClass.h" @implementation BaseClass -(void)baz { self.foo = @"test"; self.bar = 123; } @end

ChildClass.h

// this will import BaseClass.h without the class extension #import "BaseClass.h" @interface ChildClass : BaseClass -(void)test; @end

ChildClass.m

// this will implicitly import BaseClass.h from ChildClass.h, // with BaseClass_protected defined, // so it will also get the protected class extension #define BaseClass_protected #import "ChildClass.h" @implementation ChildClass -(void)test { self.foo = @"test"; self.bar = 123; [self baz]; } @end

Cuando llamas a #import , básicamente copia y pega el archivo .h al lugar donde lo estás importando. Si tiene un #ifdef , solo incluirá el código dentro si #define con ese nombre.

En su archivo .h, no establece la definición para que las clases que importan .h no vean la extensión de clase protegida. En el archivo .m de clase base y subclase, use #define antes de usar #import para que el compilador incluya la extensión de clase protegida.


Mientras que las otras respuestas son correctas, me gustaría agregar ...

Privado, protegido y público están disponibles, por ejemplo, variables como tales:

@interface MyClass : NSObject { @private int varA; @protected int varB; @public int varC; } @end


Simplemente crea un archivo .h con tu extensión de clase. Importe esto en sus archivos .m. Por cierto, esta es una gran manera de probar miembros privados sin romper la encapsulación (no digo que debas probar métodos privados :)).

// MyClassProtectedMembers.h @interface MyClass() @property (nonatomic, strong) MyPrivateObject *privateObject; - (void) privateMethod; @end

/////////////////

#import "MyClassProtectedMembers.h" @implementation MyClass // implement privateMethod here and any setters or getters with computed values @end

Aquí hay una esencia de la idea: https://gist.github.com/philosopherdog/6461536b99ef73a5c32a


Su única opción es declararlo como público en el archivo de encabezado. Si quiere mantener al menos alguna separación de métodos, puede crear una categoría y tener allí todos sus métodos y atributos protegidos, pero al final todo seguirá siendo público.

#import "MyClass.h" @interface MyClass (Protected) - (void) protectedMethods; @end


Una forma de resolver esto es volver a declarar la propiedad en la extensión de clase de su subclase, y luego agregar una declaración @dynamic para que el compilador no cree una implementación principal de esa propiedad. Entonces algo así como:

@interface SuperClass () @property (nonatomic, strong) id someProperty; @end .... @interface SubClass () @property (nonatomic, strong) id someProperty; @end @implementation SubClass @dynamic someProperty; @end

Obviamente, esto no es ideal porque duplica una declaración privada visible. Pero es bastante conveniente y útil en algunas situaciones, por lo que podría evaluar, caso por caso, los peligros que conlleva esta duplicación frente a la exposición de la propiedad en la interfaz pública.

Una alternativa, que usa Apple en UIGestureRecognizer, es declarar la propiedad en un archivo de encabezado de categoría separado denominado explícitamente como "privado" o "protegido", por ejemplo, "SomeClass + Protected.h". De esta forma, otros programadores sabrán que no deberían importar el archivo. Pero, si no controlas el código del que estás heredando, esa no es una opción.


Veo buenas respuestas para hacer que las propiedades sean visibles, pero no veo exponer los métodos abordados muy claramente en ninguna de estas respuestas. Aquí es cómo he expuesto con éxito los métodos privados a la subclase utilizando una Categoría:

SomeSuperClass.m:

@implementation SomeSuperClass -(void)somePrivateMethod:(NSString*)someArgument { ... }

SomeChildClass.h

@interface SomeChildClass : SomeSuperClass

SomeChildClass.m

@interface SomeSuperClass (exposePrivateMethod) -(void)somePrivateMethod:(NSString*)someArgument; @end @implementation SomeChildClass -(void)doSomething { [super somePrivateMethod:@"argument"]; } @end