JTO*_*JTO 11 c++ xcode objective-c wrapper objective-c++
我想在OS X上的C++项目中调用和使用Objective-C类.现在是时候开始转向所有Objective-C,但我们需要在一段时间内完成这项工作.
如何实现这一目标?任何人都可以解释并提供一个例子吗?
Objective-C++是C++的超集,就像Objective-C是C的超集一样.它受到OS X上的gcc和clang编译器的支持,允许您在C++中实例化和调用Objective-C对象和方法.只要在C++模块的实现中隐藏Objective-C头导入和类型,它就不会感染任何"纯"C++代码.
.mm是Objective-C++的默认扩展.Xcode会自动做正确的事情.
因此,例如,以下C++类返回自1970年1月1日以来的秒数:
//MyClass.h
class MyClass
{
public:
double secondsSince1970();
};
//MyClass.mm
#include "MyClass.h"
#import <Foundation/Foundation.h>
double MyClass::secondsSince1970()
{
return [[NSDate date] timeIntervalSince1970];
}
//Client.cpp
...
MyClass c;
double seconds = c.secondsSince1970();
Run Code Online (Sandbox Code Playgroud)
您很快就会发现Objective-C++的编译速度比C++慢,但正如您在上面所看到的,将其用法与少量桥接类相隔离相对容易.
我认为是Phil Jordan真正提出了最好的C++包装的Obj-C公式.但是,我认为后者,由Obj-C包装的C++更有用.我将在下面解释原因.
@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@end
Run Code Online (Sandbox Code Playgroud)
namespace people {
struct PersonImpl;
class Person
{
public:
Person();
virtual ~Person();
std::string name();
void setName(std::string name);
private:
PersonImpl *impl;
};
}
Run Code Online (Sandbox Code Playgroud)
#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
Run Code Online (Sandbox Code Playgroud)
我经常发现真正的问题不是让C++与Obj-C代码交谈,而是在两者之间来回切换.想象一个对象需要只有C++的项目,但基本的对象细节填写在Obj-C的土地上.在这种情况下,我用C++编写对象,然后创建它,以便我可以在Obj-C中与它交谈.
namespace people
{
struct PersonImpl;
class Person
{
public:
Person();
Person(Person &otherPerson);
~Person();
std:string name;
private:
PersonImpl *impl;
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
@interface Person : NSObject
@property (unsafe_unretained, nonatomic, readonly) void *impl;
@property (copy, nonatomic) NSString *name;
@end
Run Code Online (Sandbox Code Playgroud)
@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
Run Code Online (Sandbox Code Playgroud)
第二个你踏入C++的土地,如果你想避免你的整个项目充满.mm文件,你会感到有些痛苦.所以,我们只是说,如果你认为没有必要让你的C++对象退出,或者用C++对象重构Obj-C对象,你可以删除该代码.重要的是要注意,第二个Person通过void *方法从Obj-C代码中删除实例,最好使用复制构造函数或指针创建自己的副本将变为无效.