xml地图|网站地图|网站标签 [设为首页] [加入收藏]

RunTime的那些事儿,应用之给UIButton添加点击事件

来源:http://www.ccidsi.com 作者:集成介绍 人气:85 发布时间:2020-04-15
摘要:在头里的一篇随笔中曾经介绍过, 能够透过 runtime机制给已有个别类"增添"对象属性和非对象属性卡塔尔(قطر‎[详情]. 那么接下去,再给系统的 UIButton 增添三个 block 属性(毕竟在 iOS 中,

在头里的一篇随笔中曾经介绍过, 能够透过 runtime 机制给已有个别类"增添"对象属性和非对象属性卡塔尔(قطر‎[详情]. 那么接下去, 再给系统的 UIButton 增添三个 block 属性(毕竟在 iOS 中, block 是一种 id 类型卡塔尔(قطر‎, 当点击 button 时, 直接触发 block 块中的代码, 那样就能够幸免每一遍使用 UIButton 时都要调用系统的addTarget: action: forControlEvents: 方法.

本篇随笔在《iOS开拓之Runtime常用示例总计》底子上改动,地址是
「:」http://www.cocoachina.com/ios/20170301/18804.html
本篇小说首要创建的类如下:

引言:小编在接触runtime以前,以为runtime是三个可用可不用的,因为在咱们的实在付出中毕竟用的少。不过透过对runtime的连带学习和全体之后,就觉着在代码中用的真正不是累累,可是runtime能在首要的时候依然用OC(斯维夫特)解决问题棘手的时候,扶植我们转危为安。以前作者也是在明白和读书runtime以前,不停的在心里问:runtime毕竟能在哪里用到?就举个轻松的事例:大家在安装button的点击事件的时候,日常是如此设置的:

  1. 先是给急需运用的 block 类型定义贰个小名:

澳门皇家国际 1

button的点击事件

先是大家先创建一个实例类TestClass

不过如此,我们的Button注解和情势完结已经分别了,那大家可不得以设置成那样呢:

typedef void(^MHButtonActionCallBack)(UIButton *button);

澳门皇家国际 2

Button点击事件

那样当须求使用这种 bolck 类型的时候, 就没有必要把集中力放在 block 的具体内容上了, 即: 没有供给盘算 block 的传参和再次回到值类型了.

这一个类达成了NSCopying和NSCoding公约,富含公共的积极分子属性,和实例方法以至类措施,
在.m文件中

若是想完成以上的措施,就需求用到runtime了,今后就把温馨学习runtime的阅历分享给我们,假如有错误的地点,迎接大家提议。

  1. 应用iOS runtime 应用之给 NSString 增加对象属性和非对象属性中介绍的原理给UIButton"添加"一个MHButtonActionCallBack花色的品质(诚然, 这种"增多"并非严谨意义上的丰盛, 只可是是增加了一对gettersetter 方法而已卡塔尔国:

澳门皇家国际 3

一、runtime(运行时)的简介

旗帜显明,Objective-C是一门动态语言,它的函数调用(音信调用)在运作时才会实践。不难的来讲,runtime是归属C语言的API,Objective-C的骨子里工小编。点击这里能够看来runtime的开源代码以至点击这里有对Objective-C Runtime的牵线文书档案。

我们有私有成员变量和成员属性,和私家方法。
上面大家来具体介绍一下runtime的常用方法
1、利用runtime来得到类名

二、runtime的新闻机制

实际Objective-C中的方法调用,实质上正是出殡和安葬新闻。比如我们能够将叁个.m文书转载成.cpp文件。

Objective-C中的普通方法调用

上述是大家在支付中调用的平日性方法,可是我们把.m文件转载成.cpp文件会看出哪些吧?(转变方法是运用clang重写命令:clang -rewrite-objc Students.m.若是在重写命令的经过中,现身“./ViewController.h:9:9: fatal error: 'UIKit/UIKit.h' file not found”相像那样的大错特错,能够参考该大神的稿子Objective-C编写翻译成C 代码报错)。

runtime发送新闻

红箭头指向的正是新闻发送函数,在Xcode中看看的objc_msgSend是这样:

objc_msgSend

下边就先介绍下objc_msgSend中冒出的id和SEL吧:

id:(还记得大家一开首转变的.cpp文件呢,对,点击张开文件就可以看来这个音信了)

所谓的id原本是C中的构造体

大家在布局体中看见了objc_object,那么它又是怎么吗,大家得以点击这里,看到objc_object的真身,也是构造体!

太长了,截取了一部分。

咱俩得以看看objc_object那几个结构体中,饱含了八个private的isa指针,它的品类为isa_t。根据isa能够找到对象所对应的类,别的Objective-C的援用技能原理也跟那一个isa_t相关,今后再研讨。

SEL**:*在Objective-C中的selector在objc中是以SEL表示的。SEL是贰个主意接纳器,个人知道它就是贯彻哪个方法的标志,通过Objective-C中的@selector方法只怕runtime中的sel_registerName(const char str卡塔尔(قطر‎都足以得到五个SEL的章程选择器,当然越来越直白一点,SEL sel = NSSelectorFromString(@"1111"State of Qatar;也得以。

一点差异也未有于的,SEL也是三个结构体。

- setMHCallBack:(MHButtonActionCallBack)callBack { objc_setAssociatedObject(self, &_callBack, callBack, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (MHButtonActionCallBack)getMHCallBack { return (MHButtonActionCallBack)objc_getAssociatedObject(self, &_callBack);}
/**
          获取类名
          @param class 相应类
          @return NSString:类名
    */
      (NSString *)fetchClassName:(Class)class
   {
       const char *className = class_getName(class);
       return [NSString stringWithUTF8String:className];
   }

三、runtime发送音信的流程

Class:另外,我们在objc_object的构造体中,看见了Class ISA(卡塔尔;,那么Class又是何许啊?

咱们得以看来,Class是指向构造体objc_class的指针

在Xcode中,我们能够观望布局体objc_class的真身:

在runtime发送消息的整套工艺流程中,大家需求用到objc_class布局体中的super_class,methodLists,cache

自家在英特网看大神们的牵线,objc_class是后续于objc_object,不过在源码中自己只见到到截图所示的介绍。从objc_class构造体中,大家得以见到它含有了isa(指向本身类的指针卡塔尔,super_class指向父类的指针,name(类名卡塔尔(قطر‎,ivars(成员变量卡塔尔(قطر‎,methodLists(方法列表),cache(方法缓存),protocols(公约)。

Cache:首若是为了艺术的缓存。貌似的话,当方法调用的时候(新闻发送),不会直接在isa所针对的类中检索能够响应的新闻的办法,而是到cache中去搜索。要是在cache中从不找到可以能够响应的消息的主意,那么它才会去methodLists(方法列表)中搜索,况且runtime会把已经调用过得办法缓存到cache中,方便后一次调用,也是为着优化质量。更加多的有关缓存的兑现细节,能够戳这里看去,反正本身已经看的语无伦次了。

runtime发送消息的流程:就以[self  StudetsRun];那几个点子为例。首先,Xcode会将[self  StudetsRun];情势转变为runtime中的objc_msgSend,并将艺术调用者self和章程名字StudetsRun作为参数,以音讯的办法传输出去。objc_class中的isa指针,会找到对象所对应的类。在类中,首先去cache中,通过SEL来搜索相对应的Method,假诺有的话,音讯就发送成功了。假设未有,就去isa指向的类中的methodLists(方法列表)中探寻,而且runtime会把已经调用过得办法缓存到cache中。固然isa指向的类中从不应该方式,就去该类的父类中去寻找,一向找到根类NSObject中。根类中也尚无的话,要么就报相仿那样的crash音信:unrecognized selector sent to instance 0x7fd0a141afd0。说明未有找到该措施,只怕我们选择新闻的转变,可以幸免crash。

如此就足以放心大胆的应用UIButtonsetMHCallBack:getMHCallBack:形式开展赋值和取值操作了.

2、利用runtime来获得成员变量

四、runtime动态增加属性

大家掌握,分类是从未有过办法加多成员变量的,不过足以用runtime动态增多属性,还能高达明修暗度的法力,也为我们减轻难题提供了新的笔触和更加好的艺术。

runtime动态增多属性所用到的函数

1.objc_setAssociateObject:根本是为属性动态增多setter方法,第多少个参数是id类型的,即你想要在哪些属性上增加set方法,就必要传入哪个属性。首个参数key,属性上边的值和键是要每一种对应,键的体系不限(int,char都足以),不过经常会用char,因为它节本省存。第多个参数就是要加多在属性上的值了,注意那几个性情的值必需是id类型的(那int,BOOL类型的怎么办吧,稍后再说),最后叁个policy是描述值的品种,系统给我们枚举了一下三种:

policy(类型)

2.objc_getAssociateObject:该方法重即便为了动态生成getter方法,第三个属性是你要从哪个属性上边取值,第4个属性是流传一个键。

3.objc_removeAssociateObjects:从哪些属性中移除

4.比如:就为NSObject加多分类,并丰盛壹特性格name。

在.h文件中声称三个name属性,方便点语法的调用。

.h文件

在.m文件中我们须要贯彻getter,setter方法:

实现setter,getter方法

5.动态拉长根底数据类型属性(int,BOOL等):

在.h中的属性阐明:

BOOL类型的习性注解

.m文件贯彻getter,setter方法:

实现getter,setter方法

6.动态加多属性的利用:

至于runtime动态拉长的品质的行使,笔者举的例子是为button动态增进贰个block,让button的点击事件在block中运营,关于德姆o,请点击我的Demo下载吧!

  1. 为了有扶助调用, 还要把上一步"增多"的"属性", 封装到UIButton澳门皇家国际, 内部, 只暴暴露下边包车型客车章程:
/**
 获取成员变量

 @param class Class
 @return NSArray
 */
 (NSArray *)fetchIvarList:(Class)class
{
    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList(class, &count);//获取成员变量的个数count,以及数组内容

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i   ) {
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:2];
        const char *ivarName = ivar_getName(ivarList[i]);//获取成员变量的名称
        const char *ivarType = ivar_getTypeEncoding(ivarList[i]);//获取成员变量的类型
        dic[@"type"] = [NSString stringWithUTF8String:ivarType];
        dic[@"ivarName"] = [NSString stringWithUTF8String:ivarName];
        [mutableList addObject:dic];
    }
    free(ivarList);
    return [NSArray arrayWithArray:mutableList];
}

五、Category为啥不能加多成员变量

我们都明白Category(分类)是不能够增添分子变量的,这里边的缘由又是什么样吧?

在runtime中category是指向组织体objc_category的指针,此中的案由,大家还亟需在这里个objc_category构造体中动手。

Category

objc_category结构体

而大家的类在开立的时候要用到objc_class属性,大家就拿构造体objc_class和objc_category做下相比较:

objc_class结构体

由此三个构造体的对照大家就能够意识:比较于objc_class,objc_category缺少isa、super_class、ivars(成员列表)、cache等天性。在分拣中,大家得以用@property来声称属性,同不时候也宣称了setter和getter方法。然而因为objc_category中非常不足ivars(成员列表属性),所以大家爱莫能助生成成员变量(想深刻精通@property的小朋侪请点击iOS @property切磋(二卡塔尔(قطر‎: 浓重理解)。但是objc_category中有instace_method和class_method几个属性,所以分类是可以增多方法的。

其出口结果如下:

六、block的贯彻原理

block在我们的开拓中也是比较常用的,那么它的得以完结原理是什么样啊?

率先看下我们一直写的普通block代码:

block

当我们用clang重写命令重写该片段的时候,开掘会转形成如下方式:

block

大家的block的底层完毕其实也是runtime,在.cpp文件中,我们能够看出__block_impl,那么它又是何许呢?

struct __block_impl {

void *isa;

int Flags;

int Reserved;

void *FuncPtr;

};

block的落到实处就最近给我们关系这里,越来越多细节请参谋大神的篇章。

- addMHClickAction:(MHButtonActionCallBack)callBack;

澳门皇家国际 4

七、runtime拦截体系方法:

runtime拦截种类的艺术要用到多少个措施:

取得实例方法和类措施

调换三个法子

譬如,苹果出的One plusX,某个全屏图片(举个例子App的携带页)要求UI切两套图,那么我们得以用拦截系列的[UIImage imageNamed]方法,实现两套图片的互切。

图表适配

点击这里,能够下载Demo。

于今截止, 当须要给UIButton 增添点击事件的时候, 就可以一贯调用那些措施就足以了.

    • 在乎,即使用那个来得到类的积极分子变量,是不分私有和国有之分的,都会博得出来,意思也等于不管是成员变量,照旧成员属性,都足以获取的到,而且得到到的成员属性的名称是有下划线的
      3、获取类的分子属性

八、runtime动态增进方法

Objective-C是一门动态语言,基本上大家用到的控件、 数组、数据等都是以懒加载的花样加载的。在程序运营的时候才回到增多方式,动态增进的不二等秘书技的效果与利益就是去管理未达成的实例方法仍然为类方式。只要大家调用了三个空中楼阁的法未时,它就能动态拉长方法。

class_addMethod

动态增多属性须要用到class_addMethod函数,在该函数中要求大家传入cls(类名)、name(方法)、imp(implementation,完结新办法的函数,它最少要传播三个参数:self和_cmd)、types(类型)。不明白请进官方文书档案传送门。

多少个格局分别是检查类方法、实例方法是还是不是完毕

动态增加方法平时选用于:当大家想用二个类具备一种新的点子,但是不掌握类的当中贯彻的时候,我们得以加上分类,动态增进方法的效果达成。比方小编给贰个Game类动态增进方法。

动态增进方法

咱俩在函数调用:

如此那般就足以兑现动态增加方法了

不过大家在行使的长河中会开掘报了叁个警戒:PerformSelector may cause a leak because its selector is unknown。

消逝警示的情势,将performSelector方法换成这种写法:((void (*)(id, SEL, NSString *))[game methodForSelector:sel])(game, sel, @"11212");

至于这种主题材料地详细原因以致解决办法,请参谋大神博客。作者的动态增进方法的德姆o地址,请看点击这里下载吧。

runtime那部分就先分享到这里,有关后续的存档解档,字典转模型,Method Swizzling,音讯的转会,KVO的最底层,Objective-C的援引计数完毕等等后续再改善,要是作者有通晓仍然书写错误的地点,款待提议,蟹蟹!!

非常谢谢网络各位大神的篇章:

Runtime全方位装B指南

杨萧玉的Objective-C Runtime

沾满完整代码:UIButton MHExtra.h

#import <UIKit/UIKit.h>typedef void(^MHButtonActionCallBack)(UIButton *button);@interface UIButton /** * @brief replace the method 'addTarget:forControlEvents:' */- addMHCallBackAction:(MHButtonActionCallBack)callBack forControlEvents:(UIControlEvents)controlEvents;/** * @brief replace the method 'addTarget:forControlEvents:UIControlEventTouchUpInside' * the property 'alpha' being 0.5 while 'UIControlEventTouchUpInside' */- addMHClickAction:(MHButtonActionCallBack)callBack;@end
/**
 获取类的属性列表,包括私有和公有属性,以及定义再延展中的属性
 @param class Class
 @return 属性列表数组
 */
 (NSArray *)fetchPropertyList:(Class)class
{
    unsigned int count = 0;
    objc_property_t *propertyList = class_copyPropertyList(class, &count);
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i   ) {
        const char *propertyName = property_getName(propertyList[i]);
        [mutableList addObject:[NSString stringWithUTF8String:propertyName]];

    }
    free(propertyList);
    return mutableList;
}

UIButton MHExtra.m

其出口结果如下:

#import "UIButton MHExtra.h"#import <objc/runtime.h>/** * @brief add action callback to uibutton */@interface UIButton (MHAddCallBackBlock)- setMHCallBack:(MHButtonActionCallBack)callBack;- (MHButtonActionCallBack)getMHCallBack;@end@implementation UIButton (MHAddCallBackBlock)static MHButtonActionCallBack _callBack;- setMHCallBack:(MHButtonActionCallBack)callBack { objc_setAssociatedObject(self, &_callBack, callBack, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (MHButtonActionCallBack)getMHCallBack { return (MHButtonActionCallBack)objc_getAssociatedObject(self, &_callBack);}@end;@implementation UIButton /** * @brief replace the method 'addTarget:forControlEvents:UIControlEventTouchUpInside' * the property 'alpha' being 0.5 while 'UIControlEventTouchUpInside' */- addMHClickAction:(MHButtonActionCallBack)callBack { [self addMHCallBackAction:callBack forControlEvents:(UIControlEventTouchUpInside)]; [self addTarget:self action:@selector(mhTouchDownAction:) forControlEvents:(UIControlEventTouchDown)]; [self addTarget:self action:@selector(mhTouchUpAction:) forControlEvents:(UIControlEventTouchUpInside | UIControlEventTouchUpOutside | UIControlEventTouchCancel | UIControlEventTouchDragOutside)];}/** * @brief replace the method 'addTarget:forControlEvents:' */- addMHCallBackAction:(MHButtonActionCallBack)callBack forControlEvents:(UIControlEvents)controlEvents{ [self setMHCallBack:callBack]; [self addTarget:self action:@selector(mhButtonAction:) forControlEvents:controlEvents];}- mhButtonAction:(UIButton *)btn { self.getMHCallBack;}- mhTouchDownAction:(UIButton *)btn { btn.enabled = NO; btn.alpha = 0.5f;}- mhTouchUpAction:(UIButton *)btn { btn.enabled = YES; btn.alpha = 1.0f;}@end

澳门皇家国际 5

从今天启幕, 当要求给UIBuootn 增加点击事件的时候, 就没有供给先调用addTarget: action: forControlEvents:, 然后在促成个中的action 方法了, 直接:

    • 留意,获取的分子属性名称是从未下划线的,此处也不分私有和国有
      4、获取类的实例方法列表
 [btn addMHClickAction:^(UIButton *button) { NSLog(@"clicked button"); }];

就 O 了~

/**
 获取类的实例方法列表:getter,setter,对象方法等。但不能获取类方法,也就是加号方法
 @param class class
 @return 类的实例方法列表
 */

  (NSArray *)fetchMethodList:(Class)class
{
    unsigned int count = 0;
    Method *methodList = class_copyMethodList(class, &count);
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0 ; i < count; i   ) {
        Method method = methodList[i];
        SEL methodName = method_getName(method);
        [mutableList addObject:NSStringFromSelector(methodName)];
    }
    free(methodList);
    return mutableList;
}

至此, 给UIButton 加多点击事件的 block 就完了了!假诺各位有哪些好的笔触依旧对自个儿的代码有何样优化, 招待积极留言哦~

其出口结果如下:

澳门皇家国际 6

    • 留意,此中类的积极分子属性的getter,setter方法也得到不到的,但是类方式是获取不到
      5、获取类的构和列表
/**
 获取协议列表
 @param class class
 @return 协议列表
 */
 (NSArray *)fetchProtocolList:(Class)class
{
    unsigned int count = 0;
    __unsafe_unretained Protocol **protocolList = class_copyProtocolList(class, &count);
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i   ) {
        Protocol *protocol = protocolList[i];
        const char *protocolName = protocol_getName(protocol);
        [mutableList addObject:[NSString stringWithUTF8String:protocolName]];

    }
    return mutableList;
}

其出口结果是

本文由68399皇家赌场发布于集成介绍,转载请注明出处:RunTime的那些事儿,应用之给UIButton添加点击事件

关键词: 68399皇家赌场 iOS 随笔 iOS开发 事件

上一篇:通用占位图,代码块语法糖

下一篇:没有了

最火资讯