runtime:运行时机制
1. 是什么?
- 1.1 runtime是一套比较底层的纯C语言的API,runtime就是一个库,一个C语言库,包含了许多底层的C语言API
- 1.2平时我们编写的OC代码,在程序运行过程中,其实最终都是转成了runtime的C语言代码,runtime算是OC的幕后工作者,是整个OC的底层
- 1.3举个例子
oc中的代码:[Student alloc] init]经过runtime后,其实最终在底层生成C语言代码:
objc_msgSend(objc_msgSend("Student","alloc"), "init")
objc_msgSend其实就是想某个对象发送什么消息,这个函数第一个参数是类型或对象名,第二个参数是消息的名字,这些代码比较底层
2. 用过吗?怎么用?
- 2.1 runtime是属于OC的底层,可以进行一些非常底层的操作(用OC无法实现的,或者说不好实现)eg
- *在程序运行过程中,动态创建一个类,(比如KVO和KVC的底层实现)
- *在程序运行过程中,动态为某个类添加属性/方法,修改属性值,修改方法
- *遍历一个类中所有的属性和实例变量和所有方法
3.
- 3.1相关的头文件
- #import //消息发送机制,可以直接用底层函数,进行消息发送
- 3.2相关应用
- *NSCoding(归档和解挡)
- *字典转模型(利用runtime遍历模型对象的所有属性,根据属性名从字典中取出对应的值,设置到模型的属性上)
- *kvo(利用runtime动态产生一个类)
- 3.3相关函数
msg_send:给对象发送消息,来自
class_copyMethodList,遍历某个类中所有的方法,来自
class_copyIvarList,遍历某个类中所有的实例变量的方法,来自
运行时必备常识:
1.Ivar:成员变量的意思
2.Method:成员方法的意思
3.property:属性
- 你使用过Objective-C的运行时编程(Runtime Programming)么?如果使用过,你用它做了什么?你还能记得你所使用的相关的头文件或者某些方法的名称吗?
runtime 运行时的动态添加属性方法,
动态添加 set 方法
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
动态添加 get 方法
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
具体方法使用如下
#import <UIKit/UIKit.h>
@interface UIControl (ReName)
@property (nonatomic, copy) NSString *reName;
@end
UIControl+ReName.m
#import "UIControl+ReName.h"
#import <objc/runtime.h>
static const char * RENAME_CONST = "RECONST";
@implementation UIControl (ReName)
-(void)setReName:(NSString *)reName
{
objc_setAssociatedObject(self, RENAME_CONST, reName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)reName
{
return objc_getAssociatedObject(self, RENAME_CONST);
}
@end
使用方法如下
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.reName = @"my name is new button";
NSLog(@"%@",button.reName);
}
常用的方法使用名称
// 1.获得类中的所有成员变量
Ivar*ivarList =class_copyIvarList([selfclass], &count);
//2.获得方法的名字的字符串
NSSelectorFromString(_cmd)
//3.发送消息函数
objc_msgSend()
runtim 运行时 动态归档方法代码如下
调用方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Student *student = [[Student alloc] init];
student.name1 = @"sunlin";
student.age = 18;
student.name2 = @"sunlin";
student.name3 = @"sunlin";
student.name4 = @"sunlin";
student.name5 = @"sunlin";
student.name6 = @"sunlin";
student.name7 = @"sunlin";
// 归档文件的路径
NSString *filePath = [NSHomeDirectory()stringByAppendingPathComponent:@"person.archiver"];
// 判断该文件是否存在
if (![[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
// 不存在的时候,归档存储一个Student的对象
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
[archiver encodeObject:student forKey:@"student"];
[archiver finishEncoding];
BOOL success = [data writeToFile:filePath atomically:YES];
if (success) {
NSLog(@"归档成功!");
}
} else{
// 存在的时候,不再进行归档,而是解挡!
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Student *studentFromSaving = [unArchiver decodeObjectForKey:@"student"];
NSLog(@"%@, %lu", studentFromSaving.name7, studentFromSaving.age);
}
return YES;
}
Student.h
#import <Foundation/Foundation.h>
@interface Student : NSObject<NSCoding>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name1;
@property (nonatomic, copy) NSString *name2;
@property (nonatomic, copy) NSString *name3;
@property (nonatomic, copy) NSString *name4;
@property (nonatomic, copy) NSString *name5;
@property (nonatomic, copy) NSString *name6;
@property (nonatomic, copy) NSString *name7;
@end
Student.m
#import "Student.h"
#import <objc/runtime.h>
@implementation Student
-(void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
const char *name =ivar_getName(ivar);
NSString *nameStr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
id value = [self valueForKey:nameStr];
[aCoder encodeObject:value forKey:nameStr];
}
free(ivars);
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
id value = [aDecoder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
free(ivars);
}
return self;
}
@end