10

在从事开源项目时,我遇到了以下 C 函数声明和实现:

// FSNData.h
NSString *stringForMimeType(MimeType type);

@interface FSNData : NSObject
// All the expected objective-c property and instance method declarations
@end

// FSNData.m
#import "FSNData.h"

// where 'type' is an enum
// this does work as expected
NSString *stringForMimeType(MimeType type) {
    switch (type) {
        case MimeType_image_jpeg: return @"image/jpeg";
        case MimeType_image_png:  return @"image/png";
        default:
            NSLog(@"ERROR: FSNData: unknown MimeType: %d", type);

        // do not return "application/octet-stream"; instead, let the recipient guess
        // http://en.wikipedia.org/wiki/Internet_media_type
        return nil;
    }
}

@implementation

// all properties and methods defined in FSData.h implemented as expected

@end

这个例子可以很容易地重写为类级别的方法,没有任何问题。事实上,使用stringFormMimeType()sillFSNData无论如何都需要导入头文件。

查看Apple docs,它仅说明:

由于 Objective-C 建立在 ANSI C 的基础上,您可以自由地将直接 C 代码与 Objective-C 代码混合。此外,您的代码可以调用在非 Cocoa 编程接口中定义的函数,例如 /usr/include 中的 BSD 库接口。

没有提到 C 函数何时应该支持 Objective-C 方法。

在这一点上我能看到的唯一好处是调用上述函数,而不是类方法,一些 Objective-C 运行时调用将被跳过。在 的典型用例中FSNData,这不会显着提升用户(甚至可能对开发人员)的性能*。

偏爱 C 函数而不是类方法有什么好处(除了编码风格)?

*FSNData被用作FSNetworking库的一部分,所以我怀疑在任何应用程序的生命周期中都会执行成千上万的网络操作。

4

2 回答 2

12

简而言之,C(或 C++)实现非常有用:

  • 对于抽象
  • 可重用性
  • 制作中大型节目时
  • 在性能关键路径中
  • 对于“内部”实施

偏爱 C 函数而不是类方法有什么好处(除了编码风格)?

  • ObjC 消息传递引入了间接函数调用。这些是优化器的防火墙。
  • C 函数可以很容易地限制访问,而“私有”ObjC 实现可能会使用 ObjC 运行时查找,或者被意外覆盖。
  • 如果没有被引用,C 函数可能会从您的可执行文件中删除,或者它们可能会被设为私有。如果您编写可重用代码(并且您应该),这会对您的二进制大小和加载时间产生巨大影响——可能会删除未引用/未使用的 C 函数,但将保留 ObjC 类型和方法(包括它们的所有内容)参考)。这就是为什么当您只使用 ObjC 静态库的一小部分时,您的应用程序的二进制大小可能会显着增长——库中的每个 objc 类都被保留。如果该库是 C 或 C++,那么您可以通过非常小的增长来解决问题,因为您只需要引用的内容。使用 C 和 C++ 更容易证明引用或未引用的内容。
  • C 函数可以在编译期间或在链接时间优化阶段进行内联。
  • The compiler and optimizers are able to do much optimization with C functions (e.g. inter-procedural optimizations), but very little with ObjC methods because they are always indirect.
  • To avoid ObjC message dispatch overhead (as you mentioned)
  • Potential for additional reference counting operations and autorelease pool activity when interacting with ObjC objects.

Of course you won't always hurt paying for things you don't need or use -- and remember that ObjC class methods have some benefits over C functions, too. So, just look at C or C++ implementations as another tool in your toolbox. I find them very useful as complexity and project sizes increase, and they can be used to make your programs much faster. Just do what you are least likely to regret in 2015 ;)

于 2013-09-22T22:55:26.803 回答
10

您已经谈到了避免objc_msgSend调用的边际性能差异。Objective-C 的类方法也可以在子类中被覆盖,因此在 C 中实现一个方法将防止它在子类中被覆盖。相关地,由于运行时继承/多态性,Objective-C 方法永远不能内联,而 C 函数可能会被编译器内联以提高性能。

谈到objc_msgSend避免objc_msgSend.

于 2013-09-22T21:36:42.427 回答