Objective-C ++的缺点

我在Objective-C ++中为iOS编写一个大型项目。 我主要使用Objective-C用于UI和其他Apple API,而C ++用于内部audio处理和其他信息处理。 我想知道自由混合Objective-C和C ++的缺点。

当然,混合两个对象模型有其固有的局限性和潜在的混乱和混乱。 我更好奇如何使用Objective-C ++会影响编译过程,可能遇到的语法错误,可读性问题以及如何避免这些问题,等等。我有兴趣了解您的Objective-C ++经验。一直像你和提示你可能有接近这一点。

ObjC ++function非常强大 – 您可以同时select和混合所需的function,并与C,ObjC和C ++进行交互。 我已经使用了很多年了。 当然,有一些注意事项,很好的意识到它们,所以你可以尽量减less你可能遇到的问题:

汇编

当你开始创build非平凡的程序时,编译时间比ObjC或C ++高得多。

有几种常见的方法来在ObjCtypes中声明C ++types:

  • 不透明的types
  • 转发声明
  • 用智能指针转发声明
  • 按价值

我只是将这个视为一个亮点,因为从OP中推断出你对这两种语言都很熟悉。 另外,这是关于ObjC ++的更为公开的主题之一。

鉴于C ++types:

class t_thing { public: int a; }; 

你有很多方法来声明你的ivars:

不透明types:

 @interface MONClass : NSObject { void* thing; } @end 

这应该避免。 消除types安全并不好。 两个向前的选项将引入types安全。

此变体与ObjC翻译兼容。

前向声明:

 class t_thing; @interface MONClass : NSObject { t_thing* thing; } @end 

这比不透明的types更好,但是智能指针更好 – 如果你习惯于编写现代的C ++,那就很明显了。

只要您的C ++types位于全局名称空间中,此变体与ObjC翻译兼容。

使用智能指针的前向声明:

 class t_thing; @interface MONClass : NSObject { t_smart_pointer<t_thing> thing; } @end 

如果您打算设置转换防火墙(例如使用PIMPL并转发以减less依赖关系),这是最好的。 而且,ObjC对象已经经历了locking和分配,所以分配一个C ++types并不是一件坏事。 如果您有多个声明,您可能更愿意为您的实现创build一个包装types,以减less个人分配。

这个变体与ObjC翻译兼容。

现在是时候提醒你,你应该启用一个ObjC ++的编译器选项: GCC_OBJC_CALL_CXX_CDTORS 。 当这个标志被设置时会发生什么? 编译器生成隐藏的objc方法,调用你的C ++ ivars的构造函数和析构函数。 如果使用GCC_OBJC_CALL_CXX_CDTORS C ++ ivars必须是默认可构造的。 如果你不启用这个标志,你必须完全手动构build和破坏你的ivars – 如果你构造了两次或者不覆盖子类的初始化器,那么你就面临着UB。

按价值:

 #include "thing.hpp" @interface MONClass : NSObject { t_thing thing; } @end 

最高的依赖性。 这是(一般)我select的路线,我对此有些遗憾。 我刚刚移动了一些东西来使用更多的C ++,并使用智能指针(以上略)来减less依赖。

这个变体与ObjC翻译兼容。

关于现代ObjC编译器的另外一件事情:编译器在二进制文件中列出了C ++types的ivars / structure。 信不信由你,这可以消耗大量的二进制空间。

这里的要点是,程序可以采用多种forms。 您可以混合使用这些技术来减less依赖性,这是引入依赖防火墙的最好的地方之一,因为ObjC是非常dynamic的(它的方法必须在一个转换中导出),并且对象创build需要分配,locking,引入引用计数系统 – 单个对象的初始化时间已经相对较高,并且实现将始终隐藏。

如果你的程序中有很多仍然在ObjC中,并且你想保持这种状态,那么你需要使用在全局命名空间中声明的types或者通过对象工厂销售特化的不透明基types。 就我个人而言,我只是用了太多的C ++,这不是一个理想的select,而且包装实现在全球范围内很快变得令人厌烦。

同时,由于编译时间很长,反之亦然:如果可以将实现的重要部分保留为C ++,那么将节省大量编译时间。 由于这个原因和ARC(下面),你可以通过将原始Appletypes保留为CFtypes来获得很多收益,所以你可以在没有ObjC扩展的情况下继续构buildC ++程序。

句法

我很less有问题, 我保持我的C + +类非常严格:

  • 我默认禁止复制和分配。
  • 我很less为C ++types声明自定义运算符。

如果你在C ++中很棒,那么你可以避免这个问题,但是我更喜欢编译器来捕捉我犯的错误。

一个明显的问题是在ObjC消息发送中的C ++范围parsing。 这需要一个空间:

 [obj setValue:::func(a)]; // << bad [obj setValue: ::func(a)]; // << good 

可读性

我遇到的一个问题是,我从来没有find一个支持ObjC ++语法的代码格式化器。

ObjC消息

  • ObjC消息传递并按值返回:按消息返回C ++types时,需要在消息传递之前检查nil 。 如果消息对象nil ,则结果将在现代运行时(x86_64和iOS)上归零。 如果您使用该实例,则这是未定义的行为。

  • ObjC消息传递并通过引用返回:在通过引用返回C ++types时,您需要在消息传递之前检查nil 。 如果消息对象nil ,则结果将是未定义的行为(引用0/NULL )。

为了克服ObjC消息传递的问题,我通常使用这样的forms:

 - (bool)selector:(std::string&)outValue; 

对于某些内部错误,返回值为false,成功则为true。

那么你可以安全地写:

 if (![obj selector:outString]) { /* bail here */ } 

杂记

  • ARC兼容性:ObjC ++不适合ARC。 主要原因是ARC不遵循混合对象模型。 示例:如果您尝试将ObjC成员放入C ++types,编译器将拒绝ARC下的程序。 这不是一个真正的问题,因为使用ObjC ++(假设你也使用SBRM)MRC是很简单的,但是它可能是你程序生命周期中的一个问题。

  • 合成属性:您将不得不为C ++types定义属性。

  • 外部工具:除了Xcode的工具集之外,很less有能够很好地处理或识别ObjC ++的程序。 文本编辑器,IDE,实用程序。

  • Apple的工具:在Xcode的实用程序中,Xcode对ObjC ++的支持有点低。 重构(不可用),导航(改进与clang分析器),概述(是相当原始的),ObjC ++可以中断IB的公用事业,项目升级往往不被支持。