常用的底层语法(objc_get,class_get,_cmd,objc_msgSend)

一,关联 objc_get

1)建立关联:objc_setAssociatedObject;该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略;当源对象销毁,关联的对象也会被销毁

源对象: 即绑定者

关键字: 是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字

关联的对象: 绑定到源对象身上的对象

关联策略: 表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。这种关联策略是通过使用预先定义好的常量来表示的。OBJC_ASSOCIATION_ASSIGN、OBJC_ASSOCIATION_RETAIN_NONATOMIC、OBJC_ASSOCIATION_COPY_NONATOMIC等

2)获取相关联对象:objc_getAssociatedObject:该函数需要两个参数:源对象,关键字

3)断开关联:断开关联是使用objc_setAssociatedObject函数,传入关联的对象为nil值即可。

使用函数objc_removeAssociatedObjects可以断开所有关联。通常情况下不建议使用这个函数,因为他会断开所有关联。只有在需要把对象恢复到“原始状态”的时候才会使用这个函数。

 

例子:

static char objKey; 

NSArray * array =[[NSArray alloc] initWidthObjects:@"One", @"Two", @"Three", nil];

objc_setAssociatedObject(array, &objKey, @“对象”, OBJC_ASSOCIATION_RETAIN);

NSString * associatedObject = (NSString *)objc_getAssociatedObject(array, &objKey);  

 

二,class_get

1)获得实例方法: Method m1 = class_getInstanceMethod([对象 class], @selector(对象方法));

2)获得类方法: Method m2 = class_getClassMethod([类 class], @selector(类方法)); 

3)方法互调: method_exchangeImplementations(m1, m2); 即执行方法m1变成执行是m2,执行方法m2变成执行是m1

 例子:

  1.     Person * p1 = [[Person alloc] init];  
  2.     Method m1 = class_getInstanceMethod([p1 class], @selector(对象方法));  
  3.     Method m2 = class_getClassMethod([Person class], @selector(类方法));  
  4.     NSLog(@"测试前:");  
  5.     [p1 对象方法];  
  6.     [Person 类方法];  
  7.     method_exchangeImplementations(m1, m2);  
  8.     NSLog(@"测试后:");  
  9.     [p1 对象方法];  
  10.     [Person 类方法]; 

输出:

  1. 2015-11-04 13:37:08.539 02-runtime[2776:69899] 测试前:  
  2. 2015-11-04 13:37:08.539 02-runtime[2776:69899] this is a 对象方法 method  
  3. 2015-11-04 13:37:08.539 02-runtime[2776:69899] this is a 类方法 method  
  4. 2015-11-04 13:37:08.540 02-runtime[2776:69899] 测试后:  
  5. 2015-11-04 13:37:08.540 02-runtime[2776:69899] this is a 类方法 method  
  6. 2015-11-04 13:37:08.540 02-runtime[2776:69899] this is a 对象方法 method 

 

三,_cmd的用法

_cmd在Objective-C的方法中表示当前方法的selector,正如同self表示当前方法调用的对象实例。NSStringFromSelector(_cmd)得到是方法的名称

例如

static char kExtendVarKey; // 键名

- (void)someCategoryMethod

{

    NSString *extendVar = objc_getAssociatedObject(self, &kExtendVarKey);

    if(!extendVar){

        extendVar = @"someText";

        objc_setAssociatedObject(self, &kExtendVarKey, extendVar, OBJC_ASSOCIATION_COPY_NONATOMIC);

    }

}

 

等同于下面代码

- (void)someCategoryMethod

{

    NSString *extendVar = objc_getAssociatedObject(self, _cmd);

    if(!extendVar){

        extendVar = @"someText";

        objc_setAssociatedObject(self, _cmd, extendVar, OBJC_ASSOCIATION_COPY_NONATOMIC);

    }

}

 

四,objc_msgSend:该函数至少有两个参数:objc_msgSend(消息的接受者, selector, param1, param2, …);

1)概念:其实每个类中都有一张方法列表去存储这个类中有的方法,当发出objc_msgSend方法时候,就会顺着列表去找这个方法是否存在,如果不存在,则向该类的父类继续查找,直到找到位置。如果始终没有找到方法,那么就会进入到消息转发机制;objc_msgSend被分为2个过程:1)在cache中寻找SEL。2)在MethodTable寻找SEL。

例子

id returnValue = [someObject messageName:parameter]; ======》 id returnValue = objc_msgSend(someObject,@selector(messageName),paramter)

Id returnValue = [super messageName:parameter]; ======》 id returnValue = objc_msgSendSuper(someObject,@selector(messageName),paramter)

posted on 2017-04-10 13:11  mantou811  阅读(683)  评论(0编辑  收藏  举报

导航