利用Runtime 实现自动化归档

利用Runtime 实现自动化归档本文是投稿文章 作者 郑钦洪 简书 1 前言对于对象的归档 之前使用 MJ 老师的 MJExtension 框架做字典转模型的时候 直接使用宏 MJCodingImpl 就能实现对象自动实现存档和解档的方法 很是好用

欢迎大家来到IT世界,在知识的湖畔探索吧!

本文是投稿文章,作者:郑钦洪_(简书)

1.前言

对于对象的归档,之前使用MJ老师的MJExtension框架做字典转模型的时候,直接使用宏MJCodingImplementation就能实现对象自动实现存档和解档的方法,很是好用。但是有时候会遇到不需要用到字典转模型,不想使用框架时,就需要自己手动一个一个实现,有时候属性一多了,简单却繁琐的相同代码会让人觉得有点不耐烦。刚好看到袁峥老师的文章《让你快速上手Runtime》,于是自己想动手来实现用runtime,实现自动化归档,整个项目的代码GitHub。

2.对象归档

以下是一个可以跳过的步骤,简单的为自己回顾了实现对象归档的原始方法,创建一个类叫做学生类,其中学生有name,和sex属性。

/ name */

@property (nonatomic,copy) NSString *name;

/ sex */

@property (nonatomic,copy) NSString *sex;

我们要对student类的对象实现归档的时候,需要做以下的步骤

  • 类的头文件遵守

@interface StudentModel : NSObject

  • 在类的.m文件中,实现以下方法

// 存档的时候需要实现

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

[aCoder encodeObject:self.name forKey:@"name"];

[aCoder encodeObject:self.sex forKey:@"sex"];

}

// 解档的时候需要实现

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

if(self = [superinit]) {

self.name = [aDecoder decodeObjectForKey:@"name"];

self.sex = [aDecoder decodeObjectForKey:@"sex"];

}

returnself;

}

在需要存档和从文件中解析存档的对象实现

// 将student对象归档到file中

[NSKeyedArchiver archiveRootObject:student toFile:file]

// 从file存档中解析对象到student中

Student *student = [NSKeyedUnarchiver unarchiveObjectWithFile:file];

这样,只需要这三个步骤我们就简单的实现了归档。看起来好像归档的过程并不麻烦,简简单单几句话就能实现了,为何需要用到运行时呢? 在这个例子中,我们的类只有2个属性:name和sex,于是我们在存档和解档的时候分别对这两个属性进行了处理,万一这个类的属性很多呢?! 请看下面这张图

利用Runtime 实现自动化归档

坑爹啊,这后台返回的参数,一个个属性实现归档,都快把我写哭了!于是想要找到一种偷懒的方式要实现自动化归档,于是这时候,Runtime就派上用场了!

3.Runtime的使用

首先,我们需要利用运行时为我们做到的一步是,通过运行时,获取类中的所有成员属性,这里用到了运行时的方法。

OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

这里引用了袁峥老师的注释来加强对这一方法的认识

// Ivar:成员属性的意思

// 第一个参数:表示获取哪个类中的成员属性

// 第二个参数:表示这个类有多少成员属性,传入一个Int变量地址,会自动给这个变量赋值

// 返回值Ivar *:指的是一个ivar数组,会把所有成员属性放在一个数组中,通过返回的数组就能全部获取到

于是我们需要写一个方法,来返回一个数组类中的所有属性名称

// 返回self的所有对象名称

+ (NSArray *)propertyOfSelf{

unsigned int count;

// 1. 获得类中的所有成员变量

Ivar *ivarList = class_copyIvarList(self, &count);

NSMutableArray *properNames =[NSMutableArray array];

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

Ivar ivar = ivarList[i];

// 2.获得成员属性名

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

// 3.除去下划线,从第一个角标开始截取

NSString *key = [name substringFromIndex:1];

[properNames addObject:key];

}

return[properNames copy];

}

在这里,我们已经获取到类中的所有属性的名称,接着我们需要在encodeWithCoder对属性名称和属性的值进行归档操作,在这里我们遇到了一个问题,如何把属性名称和属性的值对应起来呢。

在这里我们需要知道NSStringFromSelector(方法名)返回的是一个SEL变量指向方法名中的方法

我们注意到每个属性都有两个共同的方法那就是set方法和get方法,那么我们只需要通过属性名字,创建属性名指向的方法也就是get方法,就能获取到属性名对应的值。

// 归档

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

// 取得所有成员变量名

NSArray *properNames = [[self class] propertyOfSelf];

for(NSString *propertyName inproperNames) {

// 创建指向get方法

SEL getSel = NSSelectorFromString(propertyName);

// 对每一个属性实现归档

[enCoder encodeObject:[self performSelector:getSel] forKey:propertyName];

}

}

接下来,我们需要对类实现解档方法。这里我们遇到第二个问题,如何对属性名的属性进行赋值呢?这里我们需要用到属性的set方法,利用属性名,拼接出一个set方法的字符串,并创建一个指向属性set方法的SEL变量,并且利用performSelector实现赋值

// 解档

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

// 取得所有成员变量名

NSArray *properNames = [[self class] propertyOfSelf];

for(NSString *propertyName inproperNames) {

// 创建指向属性的set方法

// 1.获取属性名的第一个字符,变为大写字母

NSString *firstCharater = [propertyName substringToIndex:1].uppercaseString;

// 2.替换掉属性名的第一个字符为大写字符,并拼接出set方法的方法名

NSString *setPropertyName = [NSString stringWithFormat:@"set%@%@:",firstCharater,[propertyName substringFromIndex:1]];

SEL setSel = NSSelectorFromString(setPropertyName);

[self performSelector:setSel withObject:[aDecoder decodeObjectForKey:propertyName]];

}

returnself;

}

就这样,我们实现了对一个类实现自动归档的类,下次需要创建一个Model类时,只要继承自我们编写的这个类,就能实现自动归档啦,是不是很轻松呢。其实拿到类的属性名可以扩展很多内容,例如我们每次打印Model类的时候,都需要一个model里的属性都拼接出来,利用我们刚刚写的代码,重写description方法,就能实现在NSLog的时候把对象里的每个属性和值都打印出来了

- (NSString *)description{

NSMutableString *descriptionString = [NSMutableString stringWithFormat:@"\n"];

// 取得所有成员变量名

NSArray *properNames = [[self class] propertyOfSelf];

for(NSString *propertyName inproperNames) {

// 创建指向get方法

SEL getSel = NSSelectorFromString(propertyName);

NSString *propertyNameString = [NSString stringWithFormat:@"%@ - %@\n",propertyName,[self performSelector:getSel]];

[descriptionString appendString:propertyNameString];

}

return[descriptionString copy];

}

4.后记

这段时间一直在学Swift和UI动画,也慢慢有了一些积累,希望在空闲之余可以跟大家分享,也希望能得到各位前辈的指点。

点击下图,参加CocoaChina最新活动

微信号:CocoaChinabbs

(长按上图,可自动识别二维码)

——–—————–————-

商务合作:

投稿邮箱:

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/99964.html

(0)
上一篇 1天前
下一篇 1天前

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信