由于 Metal Language 也是基于 C++11,而 C++ 似乎是一种经过验证的性能语言的完美契合,我希望完全绕过 Objective-C / Swift。我很想留在 C++ 领域。有没有可能?
5 回答
从技术上讲是的,但它会非常难看,并且可能会破坏其他一些 Objective-C 部分。
Objective-C 和 C++ 一样,是作为预处理器开始的。其中一个遗留问题是每个 Objective-C 方法也公开为一个 C 函数调用,该函数调用分别将对象实例和方法选择器作为前两个参数,然后以从左到右的顺序声明其他参数。
构成 Objective-C 运行时的 C 调用都NSObject
可以查找当前C 函数,该函数将被任何方法调用调用。
因此,您可以创建一个 C++ 类来获取所有 C 函数指针(它甚至可以从 C 运行时执行此操作,使其成为纯 C++ 代码而不是 Objective-C++)并直接跳转到类似的适当代码。
缺点是:Objective-C 通常使用动态分派(即在每次调用时将方法解析为 C 函数),而像键值观察这样的机制之所以起作用,是因为它使用了动态分派。如果您在其他人开始观察之前获取 C 函数指针,那么您的调用将在不通知观察者的情况下更新属性。所以你可能会破坏一些模块。
发出该警告,并假设您可以将 C++ 桥接类构建为 Objective-C++ 以获得更简单的语法,例如
class MTLArray {
id m_instance;
static NSUInteger (* s_arrayLength)(id object, SEL selector);
};
MTLArray::MTLArray() {
// assuming you use the m_ pattern for instance variables
m_instance = [MTLArray new];
// assuming you use s_ for static variables; also pretending
// the mapping from method to C function will never change —
// KVO is the most prominent exception but otherwise you can
// be exceedingly confident, albeit you'll be relying on
// empirical behaviour, not the formal contract
if(!s_arrayLength) {
s_arrayLength = [MTLArray instanceMethodForSelector:@selector(arrayLength)];
}
}
NSUInteger MTLArray::getArrayLength() {
return s_arrayLength(m_instance, @selector(arrayLength));
}
...我很方便地拒绝将结果+instanceMethodForSelector:
转换为适当的类型,因为我相信我会弄错。我倾向于退缩并typedef
在我的实际代码中引入一个中间体,但您可能更喜欢更简洁。
以下开源项目为 Metal 提供了 C++ 包装器:
不,Metal 仅作为 Objective-C API 公开。充其量,你可以用一组 Objective-C++ 类来包装它,但这只会增加开销,而不是像你想要的那样绕过 Objective-C。
如果您想使用 Objective-C API,但主要使用 C++ 工作,那么最好的选择是 Objective-C++。这只是 Objective-C,但使用 C++ 而不是 C 作为底层语言。
要将 Objective-C 类转换为 Objective-C++,只需将源文件的后缀从“.m”更改为“.mm”。(您还需要确保在链接时包含正确的 C++ 运行时库。)
一旦你这样做了,你就可以在你的 Objective-C 方法中使用 C++ 代码,包括像 std::vector 这样的模板类型以及像基于范围的 for 循环这样的 C++11 结构。
是的!Apple 现在提供官方 Metal C++ 包装器。
此下载还为一些 Foundation 和 QuartzCore 类提供了 C++ 包装器,但是您应该如何使用 MetalKit 将 C++ 类集成到应用程序中并不明显,这就是您现在可能使用的...
编辑:尝试过,我不会推荐它。今晚将我的小型 Objective-C++ 项目转换为使用它后,它不起作用,而且原因不明显(在 中崩溃sendMessage
)。
管理引用计数也比在你使用的 Objective-C++ 中做更多id<MTLWhatever>
的工作,而 ARC 会为你做这些工作。
至于从 Objective-C 对象到 C++ 对象的转换,这是一个简单的桥接转换:
// In MyClass.cpp
MyClass::~MyClass()
{
if (_buffer != nullptr)
_buffer->release();
}
void MyClass::setBuffer(MTL::Buffer* buffer)
{
if (_buffer != nullptr)
_buffer->release();
_buffer = buffer->retain();
}
// In SomeClass.mm
id<MTLBuffer> inBuf = ...;
myClass.setBuffer((__bridge MTL::Buffer*)inBuf);