是否可以拥有“仅限实施”的班级成员?

时间:2010-03-01 12:36:23

标签: objective-c cocoa xcode

这是一个初学者的问题所以请耐心等待。

我有一个使用第三方库的课程(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 个答案:

答案 0 :(得分:8)

标准做法是将opaque pointers用于库类型或自定义实现结构(因此它也称为 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 - 然后你以相同的方式转发声明它并在源文件中包含库头,它会为你提供结构定义

答案 1 :(得分: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完全兼容,因为所有内容都被声明为对象引用。其次,如果需要,将私有资料重构为单独的类更容易。最后,拥有该类以保留私有部分可以更容易地将与私有资料相关的任何逻辑或持久性与其他所有东西分开;它将使未来的重构变得更容易。

它是否是满足您需求的更好解决方案取决于您的具体要求。

答案 2 :(得分:0)

我读过自LLVM 3.0以来,您可以将接口的大括号部分(声明ivars的部分)移动到实现(.m文件,@implementation块内部)

来源: http://www.raywenderlich.com/5773/beginning-arc-in-ios-5-tutorial-part-2

(该链接是ARC教程,但这个新功能独立于ARC)。

就个人而言,我既惊讶又高兴。

编辑:事实证明它是从Xcode 4.2开始的:

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