有关runtime的一点记录

虽然很早很早就知道有这么个牛逼的存在。看过一些皮毛,看完之后哦了几声感觉高大上,仿佛看懂了。不过过了一会就不知道刚才看的是什么了!

看了看MJRefresh和YYModel源码中,看到了这个方法,使用频率挺高。记录一下,多一些认识

1、 关联对象方法

objc_setAssociatedObject / objc_getAssociatedObject
一看名字就知道,类似get和set方法。一个赋值一个取值。

来把一个对象与另外一个对象进行关联。该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略。

OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

1.OBJC_EXPORT 打包lib时,用来说明该函数是暴露给外界调用的。
2.id object 表示关联者,是一个对象,变量名理所当然也是object
3.id value 表示被关联者,变量名是value,它要关联到object上的。
4.关键字是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字。
5.关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。这种关联策略是通过使用预先定义好的常量来表示的。
关联策略我感觉我和声明属性一样,retain和copy也是对应的。

enum { OBJC_ASSOCIATION_ASSIGN = 0,
       OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
       OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
       OBJC_ASSOCIATION_RETAIN = 01401,
       OBJC_ASSOCIATION_COPY = 01403};

6.断开关联
断开关联是使用objc_setAssociatedObject函数,传入nil值即可。
使用函数objc_removeAssociatedObjects可以断开所有关联。

一个简单例子,给一个数组添加一个属性。

#import "ViewController.h"
#import <objc/runtime.h>
//关联对象的静态变量的关键字
static const NSString *associationKey = @"associationKey";
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    NSArray *arr = @[@"11", @"22", @"33"];
    NSString *str = @"44";
    
//添加一个属性对象
    objc_setAssociatedObject(arr, &associationKey, str, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    NSString *getStr = objc_getAssociatedObject(arr, &associationKey);

    NSLog(@"666_SunDePrint_999:%@\n%@", getStr, arr);
}
@end

再看一个例子
需求:自定义了分享面板,点击分享QQ或者微信后,我需要再当前页面获得分享的结果,成功或者失败。
由于是自定义view,QQ微信的图标按钮就需要自己写个button,分享结果来自微信分享SDK的回调。所以初始化自定义分享面板方法的时候,需要写个block作为参数,传递成功和失败的结果。(描述的不清楚)
由于每个按钮是没关系的,所以点击各个分享按钮后,得到各自对应的结果,需要回调到各自按钮的点击事件里。
所以就需要每个按钮有个block属性,才能在点击事件里调用控制器中的block做想做的事。

1、自定义的view,作为分享view
上面一个按钮,点击后就调用分享SDK,获得结果传递给控制器。
h

#import <UIKit/UIKit.h>

@interface ShareView : UIView

- (ShareView *)initWithFame:(CGRect)frame Result:(void (^)(BOOL result))block;

@end

m

#import "ShareView.h"
#import <objc/runtime.h>

static NSString *share_weixin_key = @"share_weixin_key";

@implementation ShareView

- (ShareView *)initWithFame:(CGRect)frame Result:(void (^)(BOOL result))block {
    
    self = [super initWithFrame:frame];
    
    if (self) {
        
        UIButton *weixinBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, frame.size.width/2, frame.size.height/2)];
        [weixinBtn setBackgroundImage:[UIImage imageNamed:@"111"] forState:0];
        [weixinBtn addTarget:self action:@selector(weixinClick:) forControlEvents:64];
        //添加一个属性对象
        objc_setAssociatedObject(weixinBtn, &share_weixin_key, block, OBJC_ASSOCIATION_COPY_NONATOMIC);
        
        [self addSubview:weixinBtn];
    }
    
    return self;
}

- (void)weixinClick:(UIButton *)sender {
    
//根据key,取出添加的属性
    void (^block)(BOOL result) = objc_getAssociatedObject(sender, &share_weixin_key);
    
    sleep(2);//模拟分享消耗2s
    //2s后,得到结果成功或者失败
    if (block) {
        block(YES);
    }
}

2、在控制器中的调用

    ShareView *share = [[ShareView alloc] initWithFame:CGRectMake(0, 100, self.view.frame.size.width, 200) Result:^(BOOL result){
        
        if (result == YES) {
            NSLog(@"666_SunDePrint_999:%@", @"分享成功");
        }else{
            NSLog(@"666_SunDePrint_999:%@", @"分享成功");
        }
    }];
    
    share.backgroundColor = [UIColor greenColor];
    [self.view addSubview:share];

这算是runtime关联对象方法的一个应用了。当然可以用别的方法传递结果啥的,我自定义的分享面板view好像有些问题。哈哈。

3、给category添加属性
一般用category都是用来添加方法用的,不能添加属性,但是有时候确实需要额外一些属性,就可以用关联方法来添加属性了。MJRefresh等三方库中经常用到。

2、获取对象所有属性方法

class_copyPropertyList 、class_copyIvarList
有2个方法用法一样,前者是获取属性方法,后者还可以额外获取成员变量。最后记得释放数组。
参数传入当前类和一个数值,获取属性后,可以给这个数值赋值,得到属性的数量。返回一个属性数组。

class_copyPropertyList 相关方法

// 获取所有属性
class_copyPropertyList
说明:使用class_copyPropertyList并不会获取无@property声明的成员变量
// 获取属性名
property_getName
// 获取属性特性描述字符串
property_getAttributes
// 获取所有属性特性
property_copyAttributeList

class_copyIvarList相关方法

// 获取所有成员变量
class_copyIvarList
// 获取成员变量名
ivar_getName
// 获取成员变量类型编码
ivar_getTypeEncoding
// 获取指定名称的成员变量
class_getInstanceVariable
// 获取某个对象成员变量的值
object_getIvar
// 设置某个对象成员变量的值
object_setIvar

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    Class selfCla = [self class];
    
    unsigned int proCunt;
    objc_property_t *pros = class_copyPropertyList(selfCla, &proCunt);
    NSLog(@"666_SunDePrint_999:%d", proCunt);
    for (int i = 0; i < proCunt; i++) {
        objc_property_t pro = pros[i];
        NSString *proName = [[NSString alloc] initWithCString:property_getName(pro) encoding:NSUTF8StringEncoding];
        NSLog(@"666_SunDePrint_999:%@", proName);
    }
    free(pros);
    
    unsigned int varCount;
    Ivar *porList = class_copyIvarList(selfCla, &varCount);
    NSLog(@"666_SunDePrint_999:%d", varCount);
    for (int i = 0; i < varCount; i++) {
        Ivar list = porList[i];
        NSString *name = [[NSString alloc] initWithCString:ivar_getName(list) encoding:NSUTF8StringEncoding];
        NSLog(@"666_SunDePrint_999--var:%@", name);
    }
    free(porList);
}

3、获取有关属性信息的结构体

property_getAttributes函数返回objc_property_attribute_t结构体列表,objc_property_attribute_t结构体包含name和value,常用的属性如下:

属性类型 name值:T value:变化
编码类型 name值:C(copy) &(strong) W(weak)空(assign) 等 value:无
非/原子性 name值:空(atomic) N(Nonatomic) value:无
变量名称 name值:V value:变化

使用property_getAttributes获得的描述是property_copyAttributeList能获取到的所有的name和value的总体描述,如 T@"NSDictionary",C,N,V_dict1

  for (int i = 0; i < proCunt; i++) {
        objc_property_t pro = pros[i];
        NSString *proName = [[NSString alloc] initWithCString:property_getName(pro) encoding:NSUTF8StringEncoding];
        
        
        const char *attrs = property_getAttributes(pro);
        NSString *propertyAttributes = @(attrs);
        NSArray *attributeItems = [propertyAttributes componentsSeparatedByString:@","];

        NSLog(@"666_SunDePrint_999:%@--%@", proName, attributeItems);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,698评论 0 9
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 2,188评论 0 7
  • Objective-C语言是一门动态语言,他将很多静态语言在编译和链接时期做的事情放到了运行时来处理。这种动态语言...
    tigger丨阅读 1,395评论 0 8
  • 对于从事 iOS 开发人员来说,所有的人都会答出【runtime 是运行时】什么情况下用runtime?大部分人能...
    梦夜繁星阅读 3,706评论 7 64
  • 我是一名初三在校生,和众多“初三狗”一样,工作日不停歇,周末还得“补习班一日游”。但今天有一个不一样的收获,在英语...
    Belief_d08d阅读 187评论 0 0