Objective C类方法与C函数

时间:2013-09-22 20:43:14

标签: objective-c c function class-method

在开发源代码项目时,我遇到了以下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()窗台无论如何都需要导入FSNData头文件。

查看the Apple docs,它仅说明:

  

因为Objective-C基于ANSI C,你可以自由地使用   使用Objective-C代码混合直接C代码。而且,你的代码   可以调用非Cocoa编程接口中定义的函数   作为/ usr / include中的BSD库接口。

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

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

在类方法上支持C函数有什么好处(编码风格除外)?

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

2 个答案:

答案 0 :(得分:11)

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

  • For Abstraction
  • 可重用性
  • 制作中型和大型节目时
  • 在绩效关键路径中
  • 对于“内部”实施
  

在类方法上支持C函数有什么好处(编码风格除外)?

  • ObjC消息传递介绍了间接函数调用。这些是优化器的防火墙。
  • C函数可以轻松限制访问,而“私有”ObjC实现可以使用ObjC运行时查找,或者意外覆盖。
  • 如果未引用C函数,则可以从可执行文件中删除它们,或者可以将它们设为私有。如果您编写可重用的代码(并且您应该),这会对您的二进制大小和加载时间产生巨大影响 - 可能会删除未引用/使用的C函数,但会保留ObjC类型和方法(包括它们的所有内容)参考)。这就是为什么当您仅使用ObjC静态库的一小部分时,您的应用程序的二进制大小可能会显着增长 - 库中的每个objc类都会被保留。如果该库是C或C ++,那么您可以获得非常小的增长,因为您只需要引用的内容。使用C和C ++更容易证明引用的内容或不引用的内容。
  • 可以在编译期间或在链接时间优化阶段内联C函数。
  • 编译器和优化器能够使用C函数进行大量优化(例如,程序间优化),但使用ObjC方法则很少,因为它们总是间接的。
  • 避免ObjC消息调度开销(如您所述)
  • 与ObjC对象交互时可能需要额外的引用计数操作和自动释放池活动。

当然,你不会总是因为你不需要或不使用的东西而付出代价 - 并且记住ObjC类方法也比C函数有一些好处。因此,只需将C或C ++实现视为工具箱中的另一个工具。我发现它们非常有用,因为复杂性和项目大小增加了,它们可以用来使程序更快。做你最不可能在2015年后悔的事情;)

答案 1 :(得分:9)

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

当谈到避免objc_msgSend时,一位聪明人曾告诉我,“如果objc_msgSend的开销对你来说太大了,那么Objective-C可能是错误的工具。”