iOS进阶回顾
2019-07-24 本文已影响0人
Coder东
runtime的介绍和使用
我们先在官方文档中查看,这个iOS中的黑魔法,runtime(运行时)底层C语言库,包含了很多C语言的API,OC在运行过程中,都会被编译器编译成runtime运行时C语言。。。
runtime有什么用?
runtime属于OC的底层实现,可以进行一些非常底层的(OC无法实现的)操作
- 利用runtime,在程序运行过程中,动态创建一个类
- 利用runtime,在程序运行过程中,动态的为某个类添加属性、方法,修改属性、方法
- 遍历一个类所有的成员变量
怎么用?
头文件: <objc/runtime>
class_copyIvarList 拷贝成员列表!!
class_getName 通过类获得(C语言字符)名称
<objc/message>
objc_msgSend
objc_msgSendSuper
两个常识:
|-- Method 成员方法(函数)
|-- Ivar 成员属性(变量)
应用场景: 归档!
KVO 底层实现原理: 利用runtime运行时
利用runtime在运行的时候动态添加创建一个对象 NSKVONotifing_XX类 类名 重写SetAge方法
[self willChangeValueForKey:@"age"];
[self didChangeValueForKey:@"age"];
Objective-C 2.0 的运行时环境叫做 Morden Runtime,iOS 和 Mac OS X 64-bit 的程序都运行在 这个环境,也就是说 Mac OS X 32-bit 的程序运行在旧的 Objective-C 1.0 的运行时环境 Legacy Runtime,这里我们只讲解 Morden Runtime。
同运行时交互主要在三个不同的地方,分别是
A.Objective-c源码(譬如:定义的Category中的新方法会在运行时自动添加到原始类)
B.NSObject的方法(isMemberClassOf等动态判定方法)
C.运行时函数。
isa指针:
NSObjective中有一个Class isa指针类型的成员变量,因为我们的对象大都直接或者间接的从NSObjective继承而来,因此都会继承这个isa成员变量,isa在运行时会指向对象的Class对象,一个类的所有对象的Class对象都是同一个(JAVA也是如此),这保证了在内存中每一个类型都有唯一的类型描述。这个Class对象中也有个isa指针,它指向了上一级父类的Class对象(元类)。
在明白了这个 isa 之后,你就可以明白在继承的时候,
A extends B,你调用 A 的方法 a(),首 先 A 的 isa 到 A 的 Class 对象中去查找 a()方法,找到了就调用,
如果没找到,就驱使 A 的 Class 对象中的 isa 到父类 B 的 Class 对象中去查找
SEL与IMP:
方法选择器SEL,我们可以通过两种方式获得:
- (SEL)@selector(方法的名字)
- (SEL)NSSelectorFromString(方法的名字的字符串)
- 另外,也可以通过(NSString*)NSStringFromSelector(SEL)函数来获取SEL所指定的方法名称字符串。
- 其实Objective-C在编译的时候,会依据每一个定义的方法的名字、参数序列,生成一个唯一的证书标识,这个标识就是SEL。因此,在运行时查询方法都是通过这个唯一标识,而不是通过方法的名字。
- Objective-C又提供了IMP类型,IMP表示指向实现方法的指针(函数指针),通过它你可以直接访问一个实现方法,从而避免了[xxx message]的静态调用方式,需要首先通过SEL确定方法,然后再通过IMP找到具体的实现方法,最后在发送消息所带来的执行效率问题。一般,如果你在多次循环中反复调用一个方法,用IMP的方式,会比直接向对象发送消息高效一些。
//
// Person.m
// TestOC
//
// Created by 随风流年 on 2019/7/24.
// Copyright © 2019 随风流年. All rights reserved.
//
#import "Person.h"
/*
@synthesize 的语义是如果你没有手动实现set方法和getter方法,编译器会自动为你加上这两个方法
*/
@implementation Person
@synthesize name;
@synthesize weight;
- (Person *)initWithWeight:(int)w{
self = [super init];
if (self) {
weight = w;
}
return self;
}
- (void)print:(NSString *)str{
NSLog(@"%@ %@",str,name);
}
- (void)dealloc{
[self setName:nil];
}
@end
main.m:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Person *person=[[Person alloc] initWithWeight:68];
person.name=@"Jetta";
SEL print_sel=NSSelectorFromString(@"print:");
IMP imp=[person methodForSelector: print_sel];
imp(person,print_sel,@"*********");
[pool drain];
return 0;
}
- 这里我们看到要获得 IMP 的指针,可以通过 NSObject 中的 methodForSelector: (SEL)方法,访 问这个指针函数,我们使用 imp(id,SEL,argument1,... ...),第一个参数是调用方法的对象,第 二个方法是方法的选择器对象,第三个参数是可变参数,表示传递方法需要的参数。