xcode 围绕 Objective-C 编写 C++ 包装器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5504559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Writing a C++ Wrapper around Objective-C
提问by JTO
I want to call and work with Objective-C classes from within a C++ project on OS X. It is time to start moving towards all Objective-C, but we need to do this over some time.
我想从 OS X 上的 C++ 项目中调用和使用 Objective-C 类。现在是开始转向所有 Objective-C 的时候了,但我们需要在一段时间内做到这一点。
How does one go about accomplishing this? Can anyone shed some light and provide an example?
如何实现这一目标?任何人都可以阐明并提供一个例子吗?
回答by Barry Wark
Objective-C++is a superset of C++, just as Objective-C is a superset of C. It is supported by both the gcc and clang compilers on OS X and allows you to instantiate and call Objective-C objects & methods from within C++. As long as you hide the Objective-C header imports and types within the implementation of a C++ module, it won't infect any of your "pure" C++ code.
Objective-C++是C++的超集,就像 Objective-C 是 C 的超集一样。 OS X 上的 gcc 和 clang 编译器都支持它,并允许您从 C++ 中实例化和调用 Objective-C 对象和方法。只要您在 C++ 模块的实现中隐藏 Objective-C 头文件导入和类型,它就不会感染您的任何“纯”C++ 代码。
.mm
is the default extension for Objective-C++. Xcode will automatically do the right thing.
.mm
是 Objective-C++ 的默认扩展。Xcode 会自动做正确的事情。
So, for example, the following C++ class returns the seconds since Jan 1., 1970:
因此,例如,以下 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();
You will quickly find that Objective-C++ is even slower to compile than C++, but as you can see above, it's relatively easy to isolate its usage to a small number of bridge classes.
您很快就会发现,Objective-C++ 的编译速度甚至比 C++ 还要慢,但正如您在上面看到的那样,将其使用隔离到少数桥接类中相对容易。
回答by Cameron Lowell Palmer
I think it was Phil Jordanthat really put forward the best C++ wrapped Obj-C formula. However, I think the latter, C++ wrapped by Obj-C is more useful. I'll explain why below.
我认为是Phil Jordan真正提出了最好的 C++ 包装的 Obj-C 公式。但是,我认为后者,由 Obj-C 包装的 C++ 更有用。我将在下面解释原因。
Wrapping an Objective-C object with C++
用 C++ 包装一个 Objective-C 对象
Person.h - The Obj-C header
Person.h - Obj-C 头文件
@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@end
PersonImpl.h - The C++ header
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 - The Obj-C++ implementation
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
Wrapping a C++ object with Objective-C
用 Objective-C 包装 C++ 对象
I often find the real problem isn't getting C++ to talk to Obj-C code, it's switching back and forth between the two where things get ugly. Imagine an object that needs to have C++-only items, but the basic object details are filled out in Obj-C land. In this case, I write the object in C++ and then make it so I can talk to it in Obj-C.
我经常发现真正的问题不是让 C++ 与 Obj-C 代码交谈,而是在两者之间来回切换,事情变得很糟糕。想象一个对象,它需要只有 C++ 项,但基本的对象详细信息是在 Obj-C 域中填写的。在这种情况下,我用 C++ 编写对象,然后制作它,以便我可以用 Obj-C 与它交谈。
Person.h - The C++ header
Person.h - C++ 头文件
namespace people
{
struct PersonImpl;
class Person
{
public:
Person();
Person(Person &otherPerson);
~Person();
std:string name;
private:
PersonImpl *impl;
}
}
Person.cpp - The C++ implementation
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 - The Obj-C header
Person.h - Obj-C 头文件
@interface Person : NSObject
@property (unsafe_unretained, nonatomic, readonly) void *impl;
@property (copy, nonatomic) NSString *name;
@end
Person.mm - The Obj-C++ implementation
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
Regarding the void *
关于空*
The second you stepped into the land of C++ you were going to feel some pain if you want to avoid your whole project being littered with .mm
files. So, let's just say, if you don't think it is ever necessary to get your C++ object back out, or reconstitute the Obj-C object with the C++ object you can remove that code. It is important to note that the second you remove the Person
instance from the Obj-C code through the void *
method you had better make your own copy with the copy constructor or the pointer will become invalid.
当您踏入 C++ 领域的那一刻,如果您想避免整个项目中堆满.mm
文件,您会感到有些痛苦。所以,让我们说,如果您认为没有必要让 C++ 对象退出,或者用 C++ 对象重新构建 Obj-C 对象,您可以删除该代码。需要注意的是,当你Person
通过这种void *
方法从 Obj-C 代码中删除实例时,你最好使用复制构造函数创建自己的副本,否则指针将变得无效,这一点很重要。
回答by Martin York
First rename your files from *.m to *.mm so you get Objective-C++
首先将您的文件从 *.m 重命名为 *.mm,以便获得 Objective-C++
I have not tired this, so it is speculation (I will tonight):
这个我没有厌倦,所以是猜测(我今晚会):
As all Objective-C++ objects (that are reference counted) are controlled via pointers so you can write a special destructor for shared pointer.
由于所有 Objective-C++ 对象(引用计数)都是通过指针控制的,因此您可以为共享指针编写一个特殊的析构函数。
template<typename T>
struct ObjCDestruct
{
void operator()(T* obj)
{
[obj release];
}
};
Now you can stick your Objective-C obects in a boost::shared_ptr
现在你可以把你的 Objective-C 对象放在 boost::shared_ptr 中
// FuncFile.M
//
int func()
{
boost::shared_ptr<MyX, ObjCDestruct<MyX> > data([[MyX alloc] init]);
[data.get() doAction1:@"HI"];
}
回答by Joe
Check out this question Calling Objective-C method from C++ method?
查看这个问题Calling Objective-C method from C++ method?
You will need to have some objective-c classes to wrap the code and expose with a C function.
您将需要一些objective-c 类来包装代码并使用C 函数公开。