以此运营时系统即Objc,发送2个message音讯.

(1)什么是Runtime ?(当然Runtime 还有为数不少用,笔者所说的只是它的冰山一角)

接下去的几篇小说会讲课到以下内容:

1.音讯机制

2.取得类的性质和方法列表

3.主意互换(方法诈骗)

4.动态方法决议(或堵住调用)

5.关联属性(associative)

   
 听着很高大尚的样板,其实过多时候大家都在用,只不过,你不驾驭而已:那么大家来归纳精通一下什么样是Runtime,我们都晓得Object-C
是依据C语言所衍生出来并追加了面向对象概念的语言.

一.runtime简练介绍.

         
Objective-C语言是一门动态语言,它将过多静态语言在编译和链接时期做的事放到了运行时来处理。那种动态语言的优势在于:大家写代码时亦可更具灵活性,如我辈得以把消息转载给大家想要的目的,或许随便沟通1个格局的落实等。  

         
那种特性意味着Objective-C不仅须求贰个编译器,还必要七个周转时系统来执行编译的代码。对于Objective-C来说,那个运营时系统就好像二个操作系统一样:它让拥有的劳作可以健康的周转。那个运转时系统即Objc
Runtime。Objc
Runtime其实是3个Runtime库,它基本上是用C和汇编写的,这些库使得C语言有了面向对象的力量。

Runtime库首要做上面几件事:

           
封装:在这几个库中,对象能够用C语言中的结构体表示,而艺术可以用C函数来落实,此外再添加了一些外加的风味。那么些结构体和函数被runtime函数封装后,我们就足以在程序运维时创制,检查,修改类、对象和它们的办法了。

            找出主意的结尾实施代码:当程序执行[object
doSomething]时,会向音讯接收者(object)发送一条音讯(doSomething),runtime会依照音信接收者是还是不是能响应该音讯而做出差别的反响。那将在末端详细介绍。

Objective-C

runtime近日有五个版本:Modern runtime和Legacy runtime。Modern Runtime
覆盖了六十个人的Mac

OS X Apps,还有 iOS Apps,Legacy Runtime 是最初用来给三十一位 Mac OS X Apps

用的,也等于可以不用管就是了

    

     
OC中全数都被规划成了目的,大家都明白3个类被开首化成壹个实例,那一个实例是二个对象。实际上2个类精神上也是三个目标,在runtime中用结构体表示。

<objc/runtime.h>框架中相关的定义:

typedef struct objc_method *Method;  //描述类中的三个情势

typedef struct objc_ivar *Ivar; //实例变量

typedef struct objc_category *Category; //类别Category

typedef struct objc_property *objc_property_t; //类中评释的质量

类在runtime中的代表:

struct objc_class {

Class isa;
//指针,顾名思义,表示是四个哪些,实例的isa指向类对象,类对象的isa指向元类

#if !__OBJC2__

Class super_class;//指向父类

const char *name;//类名

long version;

long info;

long instance_size

struct objc_ivar_list *ivars//成员变量列表

struct objc_method_list **methodLists;//方法列表

struct objc_cache *cache;//缓存,
一种优化,调用过的主意存入缓存列表,下次调用先找缓存

struct objc_protocol_list *protocols//协议列表

#endif

} OBJC2_UNAVAILABLE;

/* Use `Class` instead of `struct objc_class *` */


   
不过OC和其余面向对象的语言依旧有分其他,比如在其余语言里面叫做艺术调用,而在OC里面叫做给目标发送信息.并且OC
把数据类型的明确有编译时推迟到了运营时,大家常常调用方法 [recive
message];并不会应声执行message那些格局,而是向recive
发送多个message音讯.

二.简单运用.(待补充)

   
大家日常在先后里很简单遇到一种情状,须要一贯在改,不精晓怎么样时候,和后台研讨好的事物,过了个礼拜三,变得面目全非,貌似是流星撞了地球,而你还傻呵呵找问题出在哪?,有时候照旧招致程序直接崩溃,当然3个闻名遐迩的程序员,会想到那种景况,做各个判断,哪还有没有其余什么更好的章程呢.当然是一对,刚才也说了,程序崩溃无非是给目的发送了贰个她处理不了的标题,比如:向一个数组添加多个nil
成分;

1.消息机制

例:自定义Person类,并声称已毕方式- (void)eat,
我们在控制器中调用oc代码如下:

Person *p1 = [[Person alloc]init];

//1.1 新闻发送

[p1 eat];

貌似那种情形平昔崩给你看

oc代码在Runtime库中转化成底层c代码如下:

Class PersonClass = objc_getClass(“Person”);

//注意Class实际上也是目标,所以同样可以经受新闻,向Class发送alloc音讯

Person *p1 = objc_msgSend(PersonClass, sel_registerName(“alloc”));

//发送init消息给Person实例p1

p1 = objc_msgSend(p1, sel_registerName(“init”));

//发送eat消息给p1,即调用eat方法

objc_msgSend(p1, sel_registerName(“eat”));

//合并以上音讯传递进度

objc_msgSend(objc_msgSend(objc_msgSend(objc_getClass(“Person”),
sel_registerName(“alloc”)), sel_registerName(“init”)),
sel_registerName(“eat”));

(2)难题一挥而就-思路

什么样验证?(如何能看出编译后的文书?)

1). 打开终端。cd 到工程目录下;

cd /Users/qinlun/Desktop/runtime\ -\ 02\
新闻发送的副本/runtime-音讯发送

2). 执行 ls
查看工程目录下的公文,找到成立person对象的控制器文件ViewController.m;

3). 执行rewriteoc ViewController.m
等一会就会在工程目录得到ViewConreoller.cpp文件(该文件即为编译过的文件);

4.)用Xcode打开此.cpp文件大约在57077行可以找到如下代码;

// @interface ViewController ()

/* @end */

// @implementation ViewController

static void _I_ViewController_viewDidLoad(ViewController * self,
SEL _cmd) {

((void (*)(__rw_objc_super *, SEL))(void
*)objc_msgSendSuper)((__rw_objc_super){(id)self,
(id)class_getSuperclass(objc_getClass(“ViewController”))},
sel_registerName(“viewDidLoad”));

Person *p1 = ((Person *(*)(id, SEL))(void
*)objc_msgSend)((id)((Person *(*)(id, SEL))(void
*)objc_msgSend)((id)objc_getClass(“Person”),
sel_registerName(“alloc”)), sel_registerName(“init”));

((void (*)(id, SEL))(void *)objc_msgSend)((id)p1,
sel_registerName(“eat”));

   既然是向目的发送了1个不足处理的音信(上述图片中:是向可变数组arry
发送一条  addObject
的音讯),那么大家能否够在她们发送新闻的时候,改变一下,即便是处理不了的新闻,音信就不转正,而是在控制台打印一条音信:告诉我们奔溃原因呢.–答案自然是足以的:例如–利用Method
Swizzling==>在程序运营的时候交流五个方法的调用,例如程序要调用
addObject这些主意,那么我们让程序先调用一下要好的措施,

留意:在执行rewriteoc时应当会报错UIKit.h file not found, 处理措施:

1.进入终极,键入命令vim ~/.bash_profile;

2.在vim界面输入i进入编辑编辑状态并且键入:alias rewriteoc=’clang -x
objective-c -rewrite-objc
-isysroot/Applications/Xcode.app/Contents/Developer/Platforms/诺基亚Simulator.platform/Developer/SDKs/NokiaSimulator.sdk’;

3.键入达成,点esc退出编辑状态,再键入:wq退出vim并保存,再举行source
~/.bash_profile;

4.再实施rewriteoc xxx.m即可成功;

解决办法参见小说(
http://blog.csdn.net/majiakun1/article/details/52842010)解决


(3)难题消除-怎样贯彻

2.获取类的质量和方式列表

例:自定义类Person

Person.h文件

@interface Person : NSObject

@property (nonatomic, strong)NSString *name;

@property (nonatomic, assign) int age;

– (void)sayHello;

@end


Person.m文件

#import “Person.h”

@interface Person ()

//私有属性

@property (nonatomic, strong)NSString *address; //地址

@end

@implementation Person

– (instancetype)init{

if (self = [super init]) {

      _address = @”北戴河”;

        self.name = @”Beijing”;

        self.age = 5000;

}

return self;

}

– (NSString *)description {

        return [NSString stringWithFormat:@”address:%@, age:%f, name:
%@”, self.address,self.age ,self.name];

}

– (void)sayHello{

        NSLog(@”—–说:hello–%@”, self.address);

}

//内部私有方法

– (void)interface{

          NSLog(@”我是: %@”, self.name);

}

@end


ViewController.m中操作如下:

1.先打开你的顺序,看一下崩溃音讯,里面有一个reason 
若是您的主次是因为数组越界(取值范围超出数组的因素个数–常见难题)而夭亡,那么控制台会打印出-[__NSArrayM
objectAtIndex:]: index 1000 beyond bounds for empty array

1).获取成员变量(包罗个人)

Person *p = [[Person alloc]init];

NSLog(@”–更改前:%@–“,[oneperson description]);

unsigned int count = 0;

//那是个指针,地址为全体成员变量的数组集合,函数第二个参数传递的是count的地方,函数执行完结后会将成员变量个数存到改地址下

Ivar *members = class_copyIvarList([Person class], &count);

for (int i = 0; i < count; i++) {

    //循环获取每多个分子变量

      Ivar var = members[i];

      //获取对象的分子变量名称

      const char *memberName = ivar_getName(var);

      //获取对象的成员变量类型

      const char *memberType = ivar_getTypeEncoding(var);

      NSLog(@”–members: %p; memberName: %s; type: %s”,members,
memberName, memberType);

}

日志输入:

图片 1

察觉在Person.m中申明的品质address也得到了。

2.心心念念上面的 消息 会用到: 
大家前几日就让系统的法门,和我们自身写的章程开展置换,那么什么样交流呢:首先大家要得到那个方法,通过class_getInstanceMethod获取实例方法.(当然也有获取类措施的 
class_getClassMethod)(大家要求导入一个头文件:#import
<objc/runtime.h>)

2).修改属性值

Ivar address = members[2];

object_setIvar(p1, address, @”圆明园”);

NSLog(@”–更改后:%@–“,[oneperson description]);

日志输入:

图片 2

可以见见目的p1早先化地址北戴河被改动为了圆明园

图中__NSArrayM  和objectAtIndex是在上一步控制塞内加尔达喀尔赢得;

3).获取方式(蕴涵个人)

unsigned int count = 0;

Method *memberFuncs = class_copyMethodList([Person class],
&count);

for (int i = 0; i < count; i++) {

    //获取对象的措施名

    SEL address= method_getName(memberFuncs[i]);

    NSString *methodName = [NSString
stringWithCString:sel_getName(address)   
encoding:NSUTF8StringEncoding];

    //获取对象方法的重临值

    char *backParamType =  method_copyReturnType(memberFuncs[i]);

    NSLog(@”对象的法子有:—%d—-%@—-%s”,i, methodName,
backParamType);

}

日记输入:

图片 3


如此就得到系统中的objectAtIndex方法(因为超越数组成分个数而夭亡),通过这些点子,再去得到大家友好写的方法,与之互换调用时机.

3.措施互换(方法诈骗)

Objective-C 提供了瞬间API用于动态替换类方法大概实例方法的落到实处:

class_replaceMethod 替换类方法的概念;

method_exchangeImplementations
互换八个格局的完结(具体使用案例如下);

method_setImplementation 设置三个措施的落到实处;

注:class_replaceMethod
试图替换1个不存在的措施时候,会调用class_addMethod为此类伸张多个新方式

示范:开发中日常运到数组数据个数不鲜明的图景,一旦数组越界就会出现崩溃,对此难点得以选拔给系统的NSArray原生的章程-
(ObjectType)objectAtIndex:(NSUInteger)index替换掉;

#import “NSArray+LXZArray.h”

/运营时有关的文件

#import <objc/runtime.h>

@implementation NSArray (LXZArray)

//load方法在此文件加载进内存后就会调用

+ (void)load{

    [super load];

    //获取系统活动的主意

    Method fromeMethod =
class_getInstanceMethod(objc_getClass(“__NSArrayI”),   
@selector(objectAtIndex:));

      //获取用来替换的措施

      Method toMethod =
class_getInstanceMethod(objc_getClass(“__NSArrayI”),
@selector(lxz_objectAtIndex:));

      //方法沟通

      method_exchangeImplementations(fromeMethod, toMethod);

}

– (id)lxz_objectAtIndex:(NSInteger)index {

      if (self.count – 1 < index) {

            @try {

                  return [self lxz_objectAtIndex:index];

          } @catch (NSException *exception) {

          // 在崩溃后会打印崩溃音讯,方便大家调试。

          NSLog(@”—崩溃——- %s Crash Because Method %s 
———-\n”, class_getName(self.class),  __func__);

          NSLog(@”—崩溃—%@”, [exception callStackSymbols]);

          return nil;

        } @finally {}

  }else {

          return [self lxz_objectAtIndex:index];}

}

疑问

class_getInstanceMethod(objc_getClass(“__NSArrayI”),   
@selector(objectAtIndex:))
怎么写objc_getClass(“__NSArrayI”)而不是objc_getClass(“NSArray”)?

解答

NSArray是依据C底层CFArray/CFArrayRef落成的,NSArray 可以看做是一个CFArrayRef 的 Wrapper类.

NSArray的的确类型是__NSArrayI(Immutable)

NSMutableArray的真的类型是__NSArrayM(_internal)

此间提到到类簇概念。可以参照【iOS】类簇(class cluster)
http://www.jianshu.com/p/c60d9ffcde4b


未完待续。。。

参考:

http://www.jianshu.com/p/99af00237cb8;

http://www.cocoachina.com/ios/20150901/13173.html;

运转时交流调用方法,进行判定,假设条件不合法-打印原因;借使程序不专擅,调用系统方法

DEMO链接:
点击进入gitHub

* 使用方法

“`

把DEMO中 类目
文件夹里的文本拷贝到你的项目中,不必要引入不需求做其余任何事情.然后编译之后,没有不当,试一下数组越界,会不会崩溃,假如没有崩溃,集成已毕.

“`

相关文章