это - своего рода вопрос о новичках, поэтому терпите меня.
У меня есть класс, который использует стороннюю библиотеку (oniguruma, если это имеет значение). Я хочу, чтобы методы библиотеки были полностью украшены моим собственным, так, чтобы я мог переключить конкретную реализацию своего класса в любое время. Что-то как:
// MyClass.h
@interface MyClass : NSObject ...
- (int) doSomething;
// MyClass.m
#import "some_library.h"
@implementation MyClass
- (int) doSomething
{
//call library's specific stuff
}
Пока неплохо, но теперь я должен использовать переменную экземпляра в MyClass, который имеет некоторый определенный библиотекой тип (структура, объявленная в "some_library.h"). Конечно, я могу импортировать библиотеку прямо в интерфейсном разделе:
//MyClass.h
#import "some_library.h"
@interface MyClass : NSObject {
some_library_t blah;
}
- (int) doSomething;
@end
но это точно, чего я стараюсь избегать - делают пользователей MyClass, знающего о его деталях реализации.
Я могу так или иначе "скрыть" определенные типы библиотеки от интерфейса своего класса? Какова общепринятая практика?
Стандартной практикой является использование непрозрачных указателей либо на типы библиотеки, либо на структуру пользовательской реализации (таким образом его также называют Pimpl - указатель на реализацию ).
Для этого вы должны знать, что вы можете определять указатели на неполные типы, то есть на типы, которые вы только объявляете существующими. Например: [
struct FooImpl;
@interface Foo {
struct FooImpl* impl; // using pointer is ok for incomplete types
}
@end
] Затем вы можете определить тип в файле реализации:
struct FooImpl {
// ... member definition
};
и выделить / инициализировать его, например. в вашем методе - (id) init
.
FooImpl
также мог бы быть SomeLibraryType
, если бы тип библиотеки был структурой - затем вы должны пересылать объявление таким же образом и включать заголовок библиотеки в исходный файл, что дает вам определение структур.
Ответ gf точен, но есть и другой способ. Используйте непрозрачный класс.
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
Если вам не нравится SELF_PRIVVY, вы можете сделать что-то вроде этого:
// in Foo's @implementation
- (PrivateStuff *) privateStuff { return internalGunk; }
У вышеприведенного шаблона (всего) есть несколько преимуществ. Во-первых, он полностью совместим с GC в том смысле, что все объявлено как объектные ссылки. Во-вторых, при необходимости гораздо проще реорганизовать частные данные в отдельный класс. Наконец, наличие этого класса для удержания частных лиц упрощает отделение любой логики или настойчивости, связанных с этими частными вещами, от всего остального; это упростит будущий рефакторинг.
Будет ли это лучшее решение для ваших нужд, зависит от ваших конкретных требований.