Runtime 的个人总结
2016-06-15 00:00
399 查看
摘要: Runtime的理解
静态类型语言是指在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型,某些具有类型推导能力的现代语言可能能够部分减轻这个要求. 动态类型语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
通俗点讲,OC为了表现其动态性,尽可能的将编译链接时的一些程序工作推迟到运行时。为了方便理解这种特性,咱们看个例子:
1
1
运行程序
可以发现,程序在编译过程中没有任何问题,只有一个黄色的警告,运行时却直接崩了,报错unrecognized selector sent to instance 0x7f9390d92190,没有捕捉到方法。这就是运行时特性。试想,如果是C语言呢?
OC的Runtime铸就了运行时这种特性,我们写的代码在程序运行过程中都会被转化为Runtime的C代码执行,比如上述方法中的[self runtimeTest]会被转化为objc_msgSend(target,@selector(runtimeTest))。
这也是我们为什么经常把OC中调用方法说成发送消息。runtime中的消息发送,消息转发,动态添加等知识笔者将会在下篇博客中为大家详细讲解。
当然,要做到实现runtime的这些功能,首先我们必须要理解runtime。接下来,笔者将会通过代码示例,为大家浅谈runtime。
创建两个类做测试用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
1
2
3
4
5
6
7
1
2
3
4
1
2
3
4
今天先给大家介绍这些runtime的基本使用
什么是Runtime?
我们都知道OC是一门动态运行时的语言,何为动态语言?那什么又是静态语言呢?静态类型语言是指在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型,某些具有类型推导能力的现代语言可能能够部分减轻这个要求. 动态类型语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
通俗点讲,OC为了表现其动态性,尽可能的将编译链接时的一些程序工作推迟到运行时。为了方便理解这种特性,咱们看个例子:
新建一个工程,我们在viewDidload里面写上一个方法:
[self performSelector:@selector(runtimeTest) withObject:self];
1
1
运行程序
可以发现,程序在编译过程中没有任何问题,只有一个黄色的警告,运行时却直接崩了,报错unrecognized selector sent to instance 0x7f9390d92190,没有捕捉到方法。这就是运行时特性。试想,如果是C语言呢?
OC的Runtime铸就了运行时这种特性,我们写的代码在程序运行过程中都会被转化为Runtime的C代码执行,比如上述方法中的[self runtimeTest]会被转化为objc_msgSend(target,@selector(runtimeTest))。
这也是我们为什么经常把OC中调用方法说成发送消息。runtime中的消息发送,消息转发,动态添加等知识笔者将会在下篇博客中为大家详细讲解。
Runtime的作用
Runtime作为OC的底层实现,虽然在我们编程中并不会经常使用到它,但是,在少数一些情况下,运用Runtime机制我们可以实现很强大的功能,以下是一些可能会使用到的Runtime场景:1、如上篇博客中为类别关联对象,模拟实现给类别添加属性 2、数据模型自动绑定数据,更可实现建立基类controller, 继承该基类,只要属性名与服务器返回数据中字典key名相同, 都可直接绑定到UI,但要实现这点需要在基类controller中 做处理。 3、KVC中setValue的使用,我们知道,如果setValue但是 对象没有这个属性,程序将会直接crash,runtime就可以完 美的防守。 4.动态创建函数 5.交换函数,甚至可以交换系统函数!
当然,要做到实现runtime的这些功能,首先我们必须要理解runtime。接下来,笔者将会通过代码示例,为大家浅谈runtime。
与Runtime交互
首先在刚刚创建的工程中注释掉刚才写的代码,当然,你如果问我runtime能不能在运行时再给这个方法添加实现,从而不会被crash,这当然也是完全可以实现的。不过,我们先从runtime的基础知识看起。创建两个类做测试用。
@interface CustomClass : NSObject - (void)fun1; @implementation CustomClass - (void)fun1 { NSLog(@"fun1"); } @interface TestClass : NSObject @implementation TestClass @end @interface ClassCustomClass : NSObject{ UIButton *btn; UIView *view; NSString *varTest1; NSString *varTest2; NSString *varTest3; } @property (nonatomic, copy)NSString *varTest1; @property (nonatomic, copy)NSString *varTest2; @property (nonatomic, copy)NSString *varTest3; - (void)fun; @synthesize varTest1 = varTest1, varTest2 = varTest2, varTest3 = varTest3; - (void)fun { NSLog(@"fun"); } - (void)test { NSLog(@"test"); } - (void)test1 { NSLog(@"test1"); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1.更改对象的类、获取对象的类 Class object_setClass(id obj, Class cls) / Class object_getClass(id obj)
CustomClass *obj = [CustomClass new]; [obj fun1]; Class aClass = object_setClass(obj, [TestClass class]); NSLog(@"aClass:%@",NSStringFromClass([aClass class])); NSLog(@"obj:%@",NSStringFromClass([obj class])); /** * 此时 obj已经被转换成了TestClass对象 */ [[aClass new] fun1]; CustomClass *obj = [CustomClass new]; Class aLogClass = object_getClass(obj); NSLog(@"alogClass:%@",aLogClass); NSLog(@"objClass:%@",NSStringFromClass([obj class]));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2.获取对象的类名 constchar *object_getClassName(id obj)
CustomClass *obj = [CustomClass new]; NSString *className = [NSString stringWithUTF8String:object_getClassName(obj)]; NSLog(@"className:%@",className);
1
2
3
4
5
1
2
3
4
5
3.获取一个类的所有方法
u_int count;//无符号整形 Method *methods = class_copyMethodList([ClassCustomClass class], &count); for (int i = 0; i < count; i ++) { SEL selName = method_getName(methods[i]); NSString *selNameStr = [NSString stringWithCString:sel_getName(selName) encoding:NSUTF8StringEncoding]; NSLog(@"%@",selNameStr); }
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
4.获取所有属性名
u_int count; objc_property_t *property = class_copyPropertyList([ClassCustomClass class], &count); for (int i = 0; i < count; i ++) { const char *propertyName = property_getName(property[i]); NSString *property = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]; NSLog(@"%@",property); }
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
5.获取所有成员变量名
u_int count; Ivar *var = class_copyIvarList([ClassCustomClass class], &count); for (int i = 0; i < count; i ++) { const char *varName = ivar_getName(var[i]); NSString *var = [NSString stringWithCString:varName encoding:NSUTF8StringEncoding]; NSLog(@"var:%@",var); }
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
6.判断实例变量的类型
ClassCustomClass *obj = [ClassCustomClass new]; //运行时判断实例变量的类型 可用于自动绑定Controller Ivar var = class_getInstanceVariable(object_getClass(obj), "btn"); const char *typeEncoding = ivar_getTypeEncoding(var); NSString *varInstanceName = [NSString stringWithCString:typeEncoding encoding:NSUTF8StringEncoding]; NSLog(@"varInstanceName:%@",varInstanceName);
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
7.实现交换方法
Method method1 = class_getInstanceMethod([NSString class], @selector(lowercaseString)); Method method2 = class_getInstanceMethod([NSString class], @selector(uppercaseString)); //可能是改变了方法函数的指针 或者交换了两个方法函数的地址 method_exchangeImplementations(method1, method2); NSLog(@"%@",[@"aaaAAAAbbbBBB" lowercaseString]);
1
2
3
4
5
6
7
1
2
3
4
5
6
7
8.动态添加类的属性
//设置关联对象 objc_setAssociatedObject([ClassCustomClass class], &associatedObjectKey, @"zhangsan", OBJC_ASSOCIATION_COPY_NONATOMIC); NSString *number = objc_getAssociatedObject([ClassCustomClass class], &associatedObjectKey); NSLog(@"%@",number);
1
2
3
4
1
2
3
4
今天先给大家介绍这些runtime的基本使用
相关文章推荐