Runtime的运用和减少应用崩溃

2018 年 6 月 2 日 CocoaChina

Objective-C 是一个动态语言,它需要一个运行时系统来动态的创建类和对象、进行消息传递和转发。关于Runtime的知识大家可以参看Apple开源的Runtime代码 和Rumtime编程指南 。


本文总结一些其常用的方法。


一、新建测试Demo


我们先创建一个测试Demo如下图,其中TestClass是一个测试类,TestClass+Category是它的一个分类,NSObject+Runtime封装了一些Runtime的方法。大家可以在这里下载Demo


Demo


下面是几个类的主要部分:


TestClass.h


TestClass.m


TestClass+Category.h


TestClass+Category.m


二、Runtime的封装


接下来我们就来看看NSObject+Runtime中的内容,其对Runtime常用的方法进行了简单的封装:


Paste_Image.png


别着急,我们一个一个看。


1、获取成员变量

下面这个方法就是获取类的成员变量列表,其中包括属性生成的成员变量。我们可以用ivar_getTypeEncoding()来获取成员变量的类型,用ivar_getName()来获取成员变量的名称:


+ (NSArray *)fetchIvarList
{
   unsigned int count = 0;
   Ivar *ivarList = class_copyIvarList(self, &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];
}


使用[TestClass fetchIvarList]方法获取TestClass类的成员变量结果:


TestClass的成员变量列表


2、获取属性列表

下面这个方法获取的是属性列表,包括私有和公有属性,也包括分类中的属性:


+ (NSArray *)fetchPropertyList
{
   unsigned int count = 0;
   objc_property_t *propertyList = class_copyPropertyList(self, &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 [NSArray arrayWithArray:mutableList];
}


使用[TestClass fetchPropertyList]获取TestClass的属性列表结果:


TestClass的属性列表


3、获取实例方法

下面这个方法就是获取类的实例方法列表,包括getter, setter, 分类中的方法等:


+ (NSArray *)fetchInstanceMethodList
{
   unsigned int count = 0;
   Method *methodList = class_copyMethodList(self, &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 [NSArray arrayWithArray:mutableList];
}


使用[TestClass fetchInstanceMethodList]获取TestClass的实例方法列表的结果:


TestClass实例方法列表


4、获取类方法列表

下方这个方法就是获取类的类方法列表:


+ (NSArray *)fetchClassMethodList
{
   unsigned int count = 0;
   Method *methodList = class_copyMethodList(object_getClass(self), &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 [NSArray arrayWithArray:mutableList];
}


使用[TestClass fetchClassMethodList]获取TestClass的类方法列表的结果:


TestClass类方法列表


5、获取协议列表

下面是获取类所遵循协议列表的方法:


+ (NSArray *)fetchProtocolList
{
   unsigned int count = 0;
   __unsafe_unretained Protocol **protocolList = class_copyProtocolList(self, &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 [NSArray arrayWithArray:mutableList];
}


使用[TestClass fetchProtocolList]获取TestClass类所遵循的协议列表的结果:


TestClass的协议列表


6、给类添加一个方法

下面的方法就是给类添加方法。第一个参数是方法的SEL,第二个参数则是提供方法实现的SEL。这个可以用在找不到某个方法时就添加一个,不然有可能会崩溃。详见Demo。


+ (void)addMethod:(SEL)methodSel methodImp:(SEL)methodImp;
{
   Method method = class_getInstanceMethod(self, methodImp);
   IMP methodIMP = method_getImplementation(method);
   const char *types = method_getTypeEncoding(method);
   class_addMethod(self, methodSel, methodIMP, types);
}


7、交换实例方法

下面的方法就是将类的两个实例方法进行交换。如果将originMethod与currentMethod的方法实现进行交换的话,调用originMethod时就会执行currentMethod的内容。详见Demo。


+ (void)swapMethod:(SEL)originMethod currentMethod:(SEL)currentMethod;
{
   Method firstMethod = class_getInstanceMethod(self, originMethod);
   Method secondMethod = class_getInstanceMethod(self, currentMethod);
   method_exchangeImplementations(firstMethod, secondMethod);
}


8、交换类方法

下面的方法就是将类的两个类方法进行交换,与交换实例方法类似,详见Demo。


+ (void)swapClassMethod:(SEL)originMethod currentMethod:(SEL)currentMethod;
{
   Method firstMethod = class_getClassMethod(self, originMethod);
   Method secondMethod = class_getClassMethod(self, currentMethod);
   method_exchangeImplementations(firstMethod, secondMethod);
}


三、利用Runtime减少应用崩溃


利用交换方法可以减少程序中的崩溃,例如数组越界等等。demo里面的Safe文件夹就是一些防止崩溃的分类,直接放进工程就可以了。


Safe


补充:如果有键盘推到后台崩溃的话,需要到build phase里给NSArray+Safe.m文件加上-fno-objc-arc标识


我们看一个例子,其他的大家可以去demo里面看。


我们首先把__NSArrayIobjectAtIndex方法换成我们的ls_objectAtIndex,然后方法里面判断但是否越界,是的话直接返回nil:


[NSClassFromString(@"__NSArrayI") swapMethod:@selector(objectAtIndex:) currentMethod:@selector(ls_objectAtIndex:)];
- (id)ls_objectAtIndex:(NSUInteger)index
{
   if (index >= [self count])
   {
       return nil;
   }
   return [self ls_objectAtIndex:index];
}


然后当我们想下面这样写的时候就不会崩溃了:


NSArray *array = @[@"aa",@"ddd"];
array[5];


好了,先说到这里吧。大家可以下载我的demo详细看一下。


作者:iOS_小松哥
链接:https://www.jianshu.com/p/35971a7e8bf6


更多推荐:


登录查看更多
0

相关内容

的说法的
少标签数据学习,54页ppt
专知会员服务
202+阅读 · 2020年5月22日
MIT新书《强化学习与最优控制》
专知会员服务
279+阅读 · 2019年10月9日
已删除
AI掘金志
7+阅读 · 2019年7月8日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
实战 | 用Python做图像处理(三)
七月在线实验室
15+阅读 · 2018年5月29日
CVE-2018-7600 - Drupal 7.x 远程代码执行exp
黑客工具箱
14+阅读 · 2018年4月17日
利用 TensorFlow 实现排序和搜索算法
机器学习研究会
5+阅读 · 2017年11月23日
tensorflow项目学习路径
北京思腾合力科技有限公司
10+阅读 · 2017年11月23日
Advances in Online Audio-Visual Meeting Transcription
Arxiv
4+阅读 · 2019年12月10日
Arxiv
23+阅读 · 2018年8月3日
Arxiv
3+阅读 · 2018年2月24日
Arxiv
4+阅读 · 2018年1月19日
VIP会员
相关资讯
已删除
AI掘金志
7+阅读 · 2019年7月8日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
实战 | 用Python做图像处理(三)
七月在线实验室
15+阅读 · 2018年5月29日
CVE-2018-7600 - Drupal 7.x 远程代码执行exp
黑客工具箱
14+阅读 · 2018年4月17日
利用 TensorFlow 实现排序和搜索算法
机器学习研究会
5+阅读 · 2017年11月23日
tensorflow项目学习路径
北京思腾合力科技有限公司
10+阅读 · 2017年11月23日
Top
微信扫码咨询专知VIP会员