this is kind of a beginners question so please bear with me.
I've got a class that makes use of a third-party library (oniguruma, if that matters). I want library methods to be completely decorated by my own, so that I can switch the underlying implementation of my class anytime. Something like:
// MyClass.h
@interface MyClass : NSObject ...
- (int) doSomething;
// MyClass.m
#import "some_library.h"
@implementation MyClass
- (int) doSomething
{
//call library's specific stuff
}
So far, so good, but now I'm needing to use an instance variable in MyClass that has some library-defined type (a structure declared in "some_library.h"). Of course I can import the library right in the interface section:
//MyClass.h
#import "some_library.h"
@interface MyClass : NSObject {
some_library_t blah;
}
- (int) doSomething;
@end
but this is exactly what i'm trying to avoid - make users of MyClass aware of its implementation details.
Can I somehow "hide" library-specific types from my class' interface? What is the standard practice?
The standard practice is to use opaque pointers to either the library types or a custom implementation structure (thus its also called Pimpl - pointer to implementation).
To do that you have to know that you can define pointers to incomplete types, i.e. types that you only declare to exist. E.g.:
struct FooImpl;
@interface Foo {
struct FooImpl* impl; // using pointer is ok for incomplete types
}
@end
You can then define the type in the implementation file:
struct FooImpl {
// ... member definition
};
and allocate/initialize it e.g. in your -(id)init
method.
FooImpl
could also be SomeLibraryType
if the library type was a struct - you'd then forward declare it in the same way and include the library header in the source file, which gives you the structs definition.
gf's answer is dead on, but there is another way, too. Use an opaque class.
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
If you don't like SELF_PRIVVY, then you can do something like this:
// in Foo's @implementation
- (PrivateStuff *) privateStuff { return internalGunk; }
The above pattern (all of it) has a couple of advantages. First, it is fully compatible with GC in that everything is declared as object references. Secondly, it is much easier to refactor the private stuff into a separate class, if needed. Finally, having that class around to hold the privates makes it easier to separate out any logic or persistence related to that private stuff from everything else; it'll make future refactoring easier.
Whether or not it is a better solution for your needs depends on your specific requirements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With