ios runtime重要性_iOS进阶之runtime作用

前言

Runtime基本是用C和汇编写的,可见苹果为了动态系统的高效而作出的努力。你可以在这里下到苹果维护的开源代码。苹果和GNU各自维护一个开源的runtime版本,这两个版本之间都在努力的保持一致。Objective-C 从三种不同的层级上与 Runtime 系统进行交互,分别是通过 Objective-C 源代码,通过 Foundation 框架的NSObject类定义的方法,通过对 runtime 函数的直接调用。大部分情况下你就只管写你的Objc代码就行,runtime 系统自动在幕后辛勤劳作着。

1、概念

RunTime简称运行时,就是系统在运行的时候的一些机制,其中最主要的是消息机制。

1.动态交换两个方法的实现

2.为类别添加属性(我们知道类别是不能扩展属性的,只能扩展方法,但可以运行时实现,通过为类增加属性)

3.获取某个类的所有成员变量和成员方法

4.实现NSCoding的自动归档和自动解档

5.动态添加对象的成本变量和成员方法

作用:当硬件内存过小的时候,如果我们将每个方法都直接加到内存当中去,但是几百年不用一次,这样就造成了浪费,所有采取动态添加

6.实现字典和模型的自动转换

3、详解:

一、动态交换方法

1.在自定义类DWExchangeTwoMethod.m中

- (instancetype)init {

if (self = [super init]) {

Method workMethod = class_getInstanceMethod([DWExchangeTwoMethod class], @selector(work));

Method playMethod = class_getClassMethod([DWExchangeTwoMethod class], @selector(play));

method_exchangeImplementations(workMethod, playMethod);

}

return self;

}

- (void)play {

NSLog(@"玩...");

}

+ (void)work {

NSLog(@"工作...");

}

复制代码

抛砖引玉:可以交换方法,防止数组越界导致的崩溃

2、然后在其他类调用

DWExchangeTwoMethod *exchangeMethod = [DWExchangeTwoMethod new];

[exchangeMethod play];

复制代码

由上可以看出,调用的是play方法

但打印结果为 【玩...】,证明已经动态交换成功

二、为分类添加属性

一般情况下,分类不可以添加属性,但用runtime却可以实现

- (NSString *)height {

return objc_getAssociatedObject(self, @"height");

}

- (void)setHeight:(NSString *)height {

objc_setAssociatedObject(self, @"height", height, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

复制代码

注:

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

id object :表示关联者,是一个对象,变量名理所当然也是object

const void *key :获取被关联者的索引key

id value :被关联者,这里是一个block

objc_AssociationPolicy policy : 关联时采用的协议,有assign,retain,copy等协议,一般使用OBJC_ASSOCIATION_RETAIN_NONATOMIC

objc_getAssociatedObject(id object, const void *key)

参数解析同上

三、获取实例变量列表

unsigned int outCount = 0;

Ivar *ivars = class_copyIvarList([DWExchangeTwoMethod class], &outCount);

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

Ivar ivar = ivars[i];

const char* name = ivar_getName(ivar);

const char* type = ivar_getTypeEncoding(ivar);

NSLog(@"变量名%s :%s", name, type);

}

// 此时要注意, 尽管在ARC模式下, 取出变量后要依然手动释放内存, 利用free()方法即可:

free(ivars);

复制代码

注:

class_copyPropertyList与class_copyIvarList

class_copyPropertyList返回的仅仅是对象类的属性(@property申明的属性),而class_copyIvarList返回类的所有属性和变量(包括在@interface大括号中声明的变量)

四、实现NSCoding的自动归档和自动解档;

(不用对每个属性edcode和decode了,如果几十个属性一个个的encode和decode真的很麻烦啊,使用运行时可以遍历出每个对象的属性,数组的方式遍历eccode,decode)

#import "DWPerson.h"

#define kname @"name"

#define kidCard @"idCard"

#define kage @"age"

#define kothers @"others"

@implementation DWPerson

- (void)encodeWithCoder:(NSCoder *)aCoder {

[aCoder encodeObject:_name forKey:kname];

[aCoder encodeObject:_idCard forKey:kidCard];

[aCoder encodeInt:_age forKey:kage];

[aCoder encodeObject:_others forKey:kothers];

}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {

if (self = [super init]) {

_name = [aDecoder decodeObjectForKey:kname];

_age = [aDecoder decodeIntForKey:kage];

_idCard = [aDecoder decodeObjectForKey:kidCard];

_others = [aDecoder decodeObjectForKey:kothers];

}

return self;

}

@end

复制代码

上面每个类都要写一次,所以我们添加个分类会更加简化

#import "NSObject+ArchiveExtension.h"

#import

@implementation NSObject (ArchiveExtension)

// 先对当前类进行编码,然后对父类进行编码,如果父类是NSObject就结束编码

- (void)encode:(NSCoder *)aCoder {

// 一层层父类往上查找,对父类的属性执行归解档方法

Class c = self.class;

while (c && c != [NSObject class]) {

unsigned int outCount = 0;

Ivar *ivars = class_copyIvarList(c, &outCount);

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

Ivar ivar = ivars[i];

NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];

id value = [self valueForKey:key];

[aCoder encodeObject:value forKey:key];

}

free(ivars);

c = [c superclass];

}

}

- (void)decode:(NSCoder *)aDecoder {

Class c = self.class;

while (c && c != [NSObject class]) {

unsigned int outCount = 0;

Ivar *ivars = class_copyIvarList(c, &outCount);

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

Ivar ivar = ivars[i];

NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];

//注意与归档的顺序不同

id value = [aDecoder decodeObjectForKey:key];

[self setValue:value forKey:key];

}

free(ivars);

c = [c superclass];

}

}

@end

复制代码

这时,可以在DWPerson.m中取代之前的代码

- (void)encodeWithCoder:(NSCoder *)aCoder {

[self encode:aCoder];

}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {

if (self = [super init]) {

[self decode:aDecoder];

}

return self;

}

复制代码

当然还可以更加简洁,把NSCoding的定义成宏

#ifndef Archive_h

#define Archive_h

#import "NSObject+ArchiveExtension.h"

#define ArchiveImplemention \

\

- (instancetype)initWithCoder:(NSCoder *)aDecoder {\

if (self = [super init]) {\

[self decode:aDecoder];\

}\

return self;\

}\

\

- (void)encodeWithCoder:(NSCoder *)aCoder {\

[self encode:aCoder];\

} //最后这句不用斜线

#endif /* Archive_h */

复制代码

注:

如果有空行,需要加斜线补充

使用:

//宏定义

#import "Archive.h"

@implementation DWPerson

ArchiveImplemention

@end

复制代码

五、动态添加方法

在viewController使用

- (IBAction)clickBtn:(id)sender {

[self performSelector:@selector(play)];

}

void play(id self, SEL _cmd) {

NSLog(@"动态添加成功");

UIViewController *vc = [UIViewController new];

vc.view.backgroundColor = [UIColor redColor];

[self presentViewController:vc animated:YES completion:nil];

}

+ (BOOL)resolveInstanceMethod:(SEL)aSEL

{

if (aSEL == NSSelectorFromString(@"play")) {

class_addMethod(self, aSEL, (IMP) play, "v@:");

return YES;

}

return [super resolveInstanceMethod:aSEL];

}

复制代码

六、实现字典和模型的自动转换

获取属性的列表的方法是字典转模型的比较核心的方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值