Возможно ли иметь членов класса «только для реализации»? - PullRequest
5 голосов
/ 01 марта 2010

это вопрос для начинающих, поэтому, пожалуйста, потерпите меня.

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

Можно ли как-то "спрятать" специфичные для библиотеки типы от интерфейса моего класса? Что такое стандартная практика?

Ответы [ 3 ]

8 голосов
/ 01 марта 2010

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

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

struct FooImpl;

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

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

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

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

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

3 голосов
/ 01 марта 2010

Ответ гф мертв, но есть и другой способ. Используйте непрозрачный класс.

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 голосов
/ 17 июня 2012

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

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

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

Лично я удивлен и счастлив.

РЕДАКТИРОВАТЬ: Оказывается, это начиная с Xcode 4.2:

В чем разница между добавлением псевдоприватных иваров в расширение класса или в блок @mplementation?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...