2010-03-01 10 views
5

esto es una especie de pregunta para principiantes así que por favor tengan paciencia conmigo.¿Es posible tener miembros de clase "solo de implementación"?

Tengo una clase que hace uso de una biblioteca de terceros (oniguruma, si eso importa). Quiero que los métodos de biblioteca estén completamente decorados por mí mismo, de modo que pueda cambiar la implementación subyacente de mi clase en cualquier momento. Algo así como:

// MyClass.h 

@interface MyClass : NSObject ... 

- (int) doSomething; 


// MyClass.m 

#import "some_library.h" 

@implementation MyClass 

- (int) doSomething 
{ 
    //call library's specific stuff 
} 

Hasta ahora, todo bien, pero ahora estoy necesidad de utilizar una variable de instancia en MiClase que tiene algún tipo de biblioteca definida (una estructura declarada en "some_library.h"). Por supuesto que puedo importar la biblioteca de derecho en la sección de interfaz:

//MyClass.h 

#import "some_library.h" 

@interface MyClass : NSObject { 
    some_library_t blah; 
} 
- (int) doSomething; 
@end 

pero esto es exactamente lo que estoy tratando de evitar - hacer que los usuarios de MiClase consciente de sus detalles de implementación.

¿Puedo de alguna manera "ocultar" tipos específicos de biblioteca de la interfaz de mi clase? ¿Cuál es la práctica estándar?

Respuesta

8

La práctica habitual es utilizar opaque pointers a cualquiera de los tipos de biblioteca o una estructura personalizada aplicación (de ahí su también llamado Pimpl - puntero a la implementación).

Para hacer eso, debe saber que puede definir punteros a tipos incompletos, es decir, tipos que solo declara que existen. Ej .:

struct FooImpl; 

@interface Foo { 
    struct FooImpl* impl; // using pointer is ok for incomplete types 
}   
@end 

A continuación, puede definir el tipo en el archivo de implementación:

struct FooImpl { 
    // ... member definition 
}; 

y asignar/inicializarlo por ejemplo, en su método -(id)init.

FooImpl también podría ser SomeLibraryType si el tipo de biblioteca era una estructura - a continuación, reenviar lo declararía de la misma manera e incluiría el encabezado de la biblioteca en el archivo fuente, que le da la definición de las estructuras.

+0

Mi mal, fijo. Me he acostumbrado demasiado a la conveniencia de C++ para el uso de 'struct'. –

3

La respuesta de gf está muerta, pero hay otra manera también. Usa una clase opaca

foo.h:

@interface Foo : NSObject 
{ 
    id internalGunk; 
} 
@end 

Foo.m:

#import "Foo.h" 

@interface PrivateStuff:NSObject 
... declare ivars and/or properties and/or methods here ... 
@end 

@implementation PrivateStuff 
... any custom implementation and/or @synthesizes here ... 
@end 

#define SELF_PRIVVY ((PrivateStuff *)internalGunk) 
@implementation Foo 
... implementation here ... 
@end 

Si no te gusta SELF_PRIVVY, entonces usted puede hacer algo como esto:

// in Foo's @implementation 
- (PrivateStuff *) privateStuff { return internalGunk; } 

El el patrón anterior (todo) tiene un par de ventajas. En primer lugar, es totalmente compatible con GC porque todo se declara como referencias de objeto. En segundo lugar, es mucho más fácil refactorizar las cosas privadas en una clase separada, si es necesario. Finalmente, tener esa clase alrededor para mantener las partes privadas hace que sea más fácil separar cualquier lógica o persistencia relacionada con ese material privado de todo lo demás; Hará que la futura refactorización sea más fácil.

Si o no es una solución mejor para sus necesidades depende de sus requisitos específicos.

0

leí que ya LLVM 3.0, puede mover los soportes de sección rizado de la interfaz (el que declara los Ivars) a la aplicación (archivo .m, en el interior del bloque @implementation)

Fuente: http://www.raywenderlich.com/5773/beginning-arc-in-ios-5-tutorial-part-2

(El enlace es un tutorial de ARC, pero esta nueva característica es independiente de ARC).

Personalmente, estoy sorprendido y feliz.

EDIT: Resulta que es desde Xcode 4.2:

What's the difference between adding pseudo-private ivars in a class extension or in the @implementation block?

Cuestiones relacionadas