2010-03-01 2 views
5

Это своего рода вопрос новичков, поэтому, пожалуйста, несите меня.Возможно ли иметь членов класса «только для реализации»?

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

Могу ли я как-то «скрыть» типы, специфичные для библиотеки, из интерфейса моего класса? Какова стандартная практика?

ответ

8

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

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

struct FooImpl; 

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

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

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

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

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

+0

Мой плохо, фиксированы. Я слишком привык к удобству C++ для использования 'struct'. –

3

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

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

0

Я читал, что с LLVM 3.0, вы можете перемещать фигурные скобки сечение интерфейса (один декларирование Ивара) к реализации (.m файл, внутри @implementation блока)

Источник: http://www.raywenderlich.com/5773/beginning-arc-in-ios-5-tutorial-part-2

(Ссылка является учебником ARC, но эта новая функция не зависит от ARC).

Лично я оба поражен и счастлив.

EDIT: Оказывается, это так Xcode 4.2:

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

Смежные вопросы