Действительно ли возможно иметь участников класса “только для реализации”?

это - своего рода вопрос о новичках, поэтому терпите меня.

У меня есть класс, который использует стороннюю библиотеку (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, знающего о его деталях реализации.

Я могу так или иначе "скрыть" определенные типы библиотеки от интерфейса своего класса? Какова общепринятая практика?

5
задан user187291 1 March 2010 в 12:36
поделиться

2 ответа

Стандартной практикой является использование непрозрачных указателей либо на типы библиотеки, либо на структуру пользовательской реализации (таким образом его также называют Pimpl - указатель на реализацию ).

Для этого вы должны знать, что вы можете определять указатели на неполные типы, то есть на типы, которые вы только объявляете существующими. Например: [

struct FooImpl;

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

] Затем вы можете определить тип в файле реализации:

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

и выделить / инициализировать его, например. в вашем методе - (id) init .

FooImpl также мог бы быть SomeLibraryType , если бы тип библиотеки был структурой - затем вы должны пересылать объявление таким же образом и включать заголовок библиотеки в исходный файл, что дает вам определение структур.

8
ответ дан 13 December 2019 в 19:25
поделиться

Ответ 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 в том смысле, что все объявлено как объектные ссылки. Во-вторых, при необходимости гораздо проще реорганизовать частные данные в отдельный класс. Наконец, наличие этого класса для удержания частных лиц упрощает отделение любой логики или настойчивости, связанных с этими частными вещами, от всего остального; это упростит будущий рефакторинг.

Будет ли это лучшее решение для ваших нужд, зависит от ваших конкретных требований.

3
ответ дан 13 December 2019 в 19:25
поделиться