它为Objective-C方法添加了一个新的直接派发机制(direct dispatch mechanism)。
Direct Methods 直接方法
直接方法具有常规方法的外观,但是具有C函数的行为。 当直接方法被调用时,它直接调用它的底层实现,而不是通过objc_msgSend。
@interface KryTestPerson : NSObject
- (void)directMethod __attribute__((objc_direct));
@end
- (void)viewDidLoad {
[super viewDidLoad];
KryTestPerson * person = [[KryTestPerson alloc]init];
[self printClassMethodName:person];
}
- (void)printClassMethodName:(KryTestPerson*)person{
unsigned int count;
Method *methods = class_copyMethodList([KryTestPerson class], &count);
for (int i = 0; i < count; i++)
{
Method method = methods[i];
SEL selector = method_getName(method);
NSString *name = NSStringFromSelector(selector);
NSLog(@"%@",name);
}
}
打印结果为 init
我们可以得知,__attribute__((objc_direct))修饰的方法并不会放在类的方法列表里面.
如果您想参与直接派发,但仍希望使您的API可以从外部访问,则可以将其封装在一个C函数中。
static inline void performDirectMethod(MyClass *__unsafe_unretained object) {
[object directMethod];
}
如果交换 __attribute__((objc_direct))修饰的方法会发生什么?
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
SEL directMethodSEL = NSSelectorFromString(@"directMethod");
Method directMethod = class_getInstanceMethod([KryTestPerson class], directMethodSEL);
Method printHelloMethod = class_getInstanceMethod([ViewController class], @selector(printHello));
method_exchangeImplementations(directMethod, printHelloMethod);
KryTestPerson * person = [[KryTestPerson alloc]init];
[person directMethod];
}
- (void)printHello{
NSLog(@"printHello");
}
打印结果为 directMethod
并没有交换成功,并不会Crash.
direct属性作用的对象
注:关于
__attribute__((objc_direct_memters)):
- 指定到
@implementation上时,那些只在@implementation中定义(不包括在@interface中定义)的方法会成为direct方法 - 指定到
@interface上时,所有方法和属性都会成为direct的
编译期检查
-
不允许重写或被重写的方法指定
direct属性 -
不允许类声明未指定
direct但类实现指定了direct- 允许类声明指定但类实现未指定
-
不允许
protocol指定的方法指定direct属性 -
不允许对
id类型的对象调用direct方法 -
不允许对
direct方法使用@selector(...)
实施此功能,主要好处是减少了代码大小。 据报道,未使用的Objective-C元数据在编译后的二进制代码中多5 - 10%的比例。
一些工程师可以遍历每个SDK框架,使用objc_direct注释私有方法,并使用objc_direct_members注释私有类,这是一种逐步瘦身SDK的轻量级方法。