我认为是Phil Jordan 真正提出了最好的C++ 封装的Obj-C 公式。但是,我认为后者,由 Obj-C 包装的 C++ 更有用。我将在下面解释原因。
用 C++ 包装一个 Objective-C 对象
Person.h - Obj-C 标头
@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@end
PersonImpl.h - C++ 头文件
namespace people {
struct PersonImpl;
class Person
{
public:
Person();
virtual ~Person();
std::string name();
void setName(std::string name);
private:
PersonImpl *impl;
};
}
Person.mm - Obj-C++ 实现
#import "Person.h"
#import "PersonImpl.h"
namespace people {
struct PersonImpl
{
Person *wrapped;
};
Person::Person() :
impl(new PersonImpl())
{
impl->wrapped = [[Person alloc] init];
}
Person::~Person()
{
if (impl) {
[impl->wrapped release]; // You should turn off ARC for this file.
// -fno-objc-arc in Build Phases->Compile->File options
}
delete impl;
}
std::string Person::name()
{
return std::string([impl->wrapped UTF8String]);
}
void Person::setName(std::string name)
{
[impl->wrapped setName:[NSString stringWithUTF8String:name.c_str()]];
}
}
@implementation Person
@end
用 Objective-C 包装一个 C++ 对象
我经常发现真正的问题不是让 C++ 与 Obj-C 代码对话,而是在两者之间来回切换,这让事情变得很糟糕。想象一个对象需要只有 C++ 的项目,但基本的对象细节是在 Obj-C 域中填写的。在这种情况下,我用 C++ 编写对象,然后制作它以便我可以在 Obj-C 中与它对话。
Person.h - C++ 头文件
namespace people
{
struct PersonImpl;
class Person
{
public:
Person();
Person(Person &otherPerson);
~Person();
std:string name;
private:
PersonImpl *impl;
}
}
Person.cpp - C++ 实现
namespace people
{
struct PersonImpl
{
// I'll assume something interesting will happen here.
};
Person::Person() :
impl(new PersonImpl())
{
}
Person::Person(Person &otherPerson) :
impl(new PersonImpl()),
name(otherPerson.name)
{
}
~Person()
{
delete impl;
}
}
Person.h - Obj-C 标头
@interface Person : NSObject
@property (unsafe_unretained, nonatomic, readonly) void *impl;
@property (copy, nonatomic) NSString *name;
@end
Person.mm - Obj-C++ 实现
@interface Person ()
@property (unsafe_unretained, nonatomic) std::shared_ptr<people::Person> impl;
@end
@implementation Person
- (instancetype)init
{
self = [super init];
if (self) {
self.impl = std::shared_ptr<people::Person>(new people::Person());
}
return self;
}
- (instancetype)initWithPerson:(void *)person
{
self = [super init];
if (self) {
people::Person *otherPerson = static_cast<people::Person *>(person);
self.impl = std::shared_ptr<people::Person>(new people::Person(*otherPerson));
}
return self;
}
- (void)dealloc
{
// If you prefer manual memory management
// delete impl;
}
- (void *)impl
{
return static_cast<void *>(self.impl.get());
}
- (NSString *)name
{
return [NSString stringWithUTF8String:self.impl->name.c_str()];
}
- (void)setName:(NSString *)name
{
self.impl->name = std::string([name UTF8String]);
}
@end
关于 void *
如果您想避免整个项目被.mm 文件乱扔,那么您踏入C++ 领域的那一刻就会感到有些痛苦。所以,我们只是说,如果您认为没有必要将您的 C++ 对象取出,或者用 C++ 对象重新构建 Obj-C 对象,您可以删除该代码。需要注意的是,第二次通过 void * 方法从 Obj-C 代码中删除 Person 实例时,最好使用复制构造函数制作自己的副本,否则指针将失效。