Objective C类方法与C函数

Mik*_*e D 9 c function objective-c 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
Run Code Online (Sandbox Code Playgroud)

这个例子很容易被重写为类级方法,没有任何问题.实际上,使用stringFormMimeType()sill FSNData无论如何都需要导入头文件.

看一下Apple文档,它只说明:

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

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

我可以在此时看到唯一的好处是,调用上述功能,而不是一个类的方法,一些Objective-C运行呼叫(一个或多个)将被跳过.在典型使用情况下FSNData,这不会给性能给用户带来明显的提升(甚至可能给开发商)*.

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

*FSNData作为的一部分FSNetworking库,所以我怀疑在过程中的任何应用程序的生命周期正在执行数以千计的网络运营会有数千人.

jus*_*tin 12

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

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

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

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

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


ipm*_*mcc 9

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

当谈到避免时objc_msgSend,一位有智慧的人曾告诉我,"如果开销objc_msgSend对你来说太大,那么Objective-C可能就是这项工作的错误工具."