iOS学习
前言
YYModel是YYKit的高效组件之一,在实际场景中的非常实用,在项目中使用MVC架构时,可以简化数据处理。在性能上相比JSONMode更加高效。在此对使用做简单学习。
优势
原作者给出如下YYModel的优势:
- 高性能:转换效率接近手写代码。
- 自动类型转换:对象类型能自动转换。
- 类型安全:在转换过程中所有的类型都会被验证,以确保类型安全。
- 非侵入性:不需要让模型类继承自基类。
- 轻量级:整个库只包含5个文件。
- 文档和测试覆盖:100%文档覆盖,99.6代码覆盖。
使用方法
简单的Model与JSON互转
这里需要注意:
当 JSON/Dictionary 中的对象类型与 Model 属性不一致时,YYModel 将会进行如下自动转换。自动转换不支持的值将会被忽略,以避免各种潜在的崩溃问题。
JSON/Dictionary | Model |
---|---|
NSString | NSNumber,NSURL,SEL,Class |
NSNumber | NSString |
NSString/NSNumber | 基础类型 (BOOL,int,float,NSUInteger,UInt64,...) NaN 和 Inf 会被忽略 |
NSString | NSDate 以下列格式解析: yyy-MM-dd yyyy-MM-dd HH:mm:ss yyyy-MM-dd'T'HH:mm:ss yyyy-MM-dd'T'HH:mm:ssZ EEE MMM dd HH:mm:ss Z yyyy |
NSDate | NSString 格式化为 ISO8601: "YYYY-MM-dd'T'HH:mm:ssZ" |
NSValue | struct (CGRect,CGSize,...) |
NSNull | nil,0 |
"no","false",... | @(NO),0 |
"yes","true",... | @(YES),1 |
多样化的数据类型交换
YYModel支持自定义的属性名进行映射,即数据的key和属性名可以是不相同。那么怎么才知道你自定义的属性名对应的是数据的哪个key呢?那就需要对自定义属性的映射进行映射声明。
objectivec
+ (NSDictionary *)modelCustomPropertyMapper {
// 将personId映射到key为id的数据字段
return @{@"personId":@"id"};
}
可以看到model和JSON获取的字典内容并不完全相同,这时候需要我们重写modelCustomPropertyMapper这个方法,使用一个字典将Model属性名对映射到 JSON 的 Key。这就是映射声明。
objectivec
+ (NSDictionary *)modelCustomPropertyMapper {
// 映射可以设定多个映射字段
return @{@"realComments":@[@"long_comments",@"comments",@"short_comments"]};
}
objectivec
// ViewController.m
Model *model = [Model modelWithDictionary:dic];
NSLog(@"realComments: %d",model.realComments);
你可以把一个或一组 json key (key path) 映射到一个或多个属性。如果一个属性没有映射关系,那默认会使用相同属性名作为映射。
在 json->model 的过程中:如果一个属性对应了多个 json key,那么转换过程会按顺序查找,并使用第一个不为空的值。
在 model->json 的过程中:如果一个属性对应了多个 json key (key path),那么转换过程仅会处理第一个 json key (key path);如果多个属性对应了同一个 json key,则转换过过程会使用其中任意一个不为空的值。
容器类数据交换
需要注意:要遵从< YYModel>协议,才会快捷提醒以下方法:
objectivec
+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;
+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;
+ (nullable NSArray<NSString *> *)modelPropertyWhitelist;
+ (nullable NSArray<NSString *> *)modelPropertyBlacklist;
如果Model是用一个容器类进行包装的话,我们就需要重写modelContainerPropertyGenericClass
这个方法返回对应容器之中的Model类型
objectivec
JSON:
{
"date": "20241020",
"stories": [
{
"image_hue": "0xaa7246",
"title": "小事 ·「谢谢,这歌儿真好听,谢谢。」",
"url": "https://daily.zhihu.com/story/9776246",
"hint": "VOL.1594",
"ga_prefix": "102007",
"images": [
"https://pica.zhimg.com/v2-36a74af2cbeb2950e23f4a21ae7c9afc.jpg?source=8673f162"
],
"type": 0,
"id": 9776246
},
{
"image_hue": "0x3d342b",
"title": "很多人都认为大学知识跟高中没有关系,那为什么还要上高中呢?为什么不能初中毕业直接上大学?",
"url": "https://daily.zhihu.com/story/9776259",
"hint": "荆公门下东坡首徒 · 10 分钟阅读",
"ga_prefix": "102007",
"images": [
"https://picx.zhimg.com/v2-f1f397a7fa6a1062bee7edd106c49496.jpg?source=8673f162"
],
"type": 0,
"id": 9776259
},
{
"image_hue": "0x3d342b",
"title": "武松血溅鸳鸯楼时,张都监的手下为什么不来帮忙?",
"url": "https://daily.zhihu.com/story/9776265",
"hint": "娃娃鱼 · 6 分钟阅读",
"ga_prefix": "102007",
"images": [
"https://picx.zhimg.com/v2-f1f397a7fa6a1062bee7edd106c49496.jpg?source=8673f162"
],
"type": 0,
"id": 9776265
},
{
"image_hue": "0x3d342b",
"title": "这世界上最毒的物质是什么?",
"url": "https://daily.zhihu.com/story/9776272",
"hint": "mekdull · 47 分钟阅读",
"ga_prefix": "102007",
"images": [
"https://picx.zhimg.com/v2-f1f397a7fa6a1062bee7edd106c49496.jpg?source=8673f162"
],
"type": 0,
"id": 9776272
}
],
"top_stories": [
{
"image_hue": "0x42535e",
"hint": "作者 / 赵学浩",
"url": "https://daily.zhihu.com/story/9776126",
"image": "https://picx.zhimg.com/v2-00604b295890258d35108f32921dfdf2.jpg?source=8673f162",
"title": "《封神演义》为什么没有列入四大名著?",
"ga_prefix": "101607",
"type": 0,
"id": 9776126
},
{
"image_hue": "0xaa7246",
"hint": "作者 / 田可乐",
"url": "https://daily.zhihu.com/story/9776246",
"image": "https://picx.zhimg.com/v2-520eb91c117bf9da4f62071961629b85.jpg?source=8673f162",
"title": "小事 ·「谢谢,这歌儿真好听,谢谢。」",
"ga_prefix": "102007",
"type": 0,
"id": 9776246
},
{
"image_hue": "0x8e6238",
"hint": "作者 / 赵泠",
"url": "https://daily.zhihu.com/story/9776243",
"image": "https://picx.zhimg.com/v2-e10faf6e06d42ddaae06fc8dc6e648b8.jpg?source=8673f162",
"title": "人类以外的动物有没有把自己的食物驯化得好吃的行为?",
"ga_prefix": "101907",
"type": 0,
"id": 9776243
},
{
"image_hue": "0x1a1b37",
"hint": "作者 / 朱锦平",
"url": "https://daily.zhihu.com/story/9776238",
"image": "https://pic1.zhimg.com/v2-5ea4434e6ba5a4e1810059ae1c6c052e.jpg?source=8673f162",
"title": "黑洞周围的「事件视界」是什么?",
"ga_prefix": "101807",
"type": 0,
"id": 9776238
},
{
"image_hue": "0xb39e74",
"hint": "作者 / 南行兮",
"url": "https://daily.zhihu.com/story/9776232",
"image": "https://picx.zhimg.com/v2-aaa227e7ccc5781303cc1d8e885b9768.jpg?source=8673f162",
"title": "我为什么总觉得辛弃疾用典的词写的很一般,而不用典的写的很好?",
"ga_prefix": "101707",
"type": 0,
"id": 9776232
}
]
}
@class Stories, Top_stories;
@interface Model
@property NSString *date;
@property NSArray *stories;
@property NSArray *top_stories;
@end
@implementation Model
// 返回容器类中的所需要存放的数据类型 (以 Class 或 Class Name 的形式)。
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"stories" : [stories class],
@"top_stories" : top_stories.class,
}
@end
打印结果:
objectivec
{
date = 20241021;
stories = (
{
"ga_prefix" = 102107;
hint = "\U8c46\U5b50 \U00b7 2 \U5206\U949f\U9605\U8bfb";
id = 9775499;
"image_hue" = 0x5d6341;
images = (
"https://pic1.zhimg.com/v2-241803af186704cf830cb0a3ad9268d2.jpg?source=8673f162"
);
title = "\U5728\U4e2d\U56fd\U53e4\U4ee3\Uff0c\U7834\U4ea7\U7684\U7537\U4eba\U7684\U4f8d\U59be\U5982\U4f55\U81ea\U5904\Uff1f";
type = 0;
url = "https://daily.zhihu.com/story/9775499";
},
{
"ga_prefix" = 102107;
hint = "\U674e\U7965JasonLee \U00b7 3 \U5206\U949f\U9605\U8bfb";
id = 9776310;
"image_hue" = 0x261e1b;
images = (
"https://picx.zhimg.com/v2-aa2257309051a31b36501c840bf8cfaa.jpg?source=8673f162"
);
title = "\U4e4b\U524d\U542c\U8bf4\U589e\U808c\U8981\U505a\U5230\U529b\U7aed\Uff0c\U4e3a\U4ec0\U4e48\U73b0\U5728\U53c8\U63d0\U5021\U300c\U4e0d\U529b\U7aed\U300d\U4e86\Uff1f";
type = 0;
url = "https://daily.zhihu.com/story/9776310";
},
{
"ga_prefix" = 102107;
hint = "\U859b\U52a8\U8c14\U7684\U55b5 \U00b7 3 \U5206\U949f\U9605\U8bfb";
id = 9776311;
"image_hue" = 0x191924;
images = (
"https://pic1.zhimg.com/v2-3673082d8ee90b155a4ecd2b556954a4.jpg?source=8673f162"
);
title = "\U8bba\U6587\U5e38\U7528\U8bcd\U6c47 i.e.\Uff0ce.g.\Uff0cetc.\Uff0cviz.\Uff0cet al. \U7684\U524d\U4e16\U4eca\U751f";
type = 0;
url = "https://daily.zhihu.com/story/9776311";
},
{
"ga_prefix" = 102106;
hint = "VOL.3454";
id = 9776346;
"image_hue" = 0xb3b3b3;
images = (
"https://pic1.zhimg.com/v2-b8a38efaf99a864356cef394c26becc0.jpg?source=8673f162"
);
title = "\U778e\U626f \U00b7 \U5982\U4f55\U6b63\U786e\U5730\U5410\U69fd";
type = 0;
url = "https://daily.zhihu.com/story/9776346";
}
);
"top_stories" = (
{
"ga_prefix" = 101607;
hint = "\U4f5c\U8005 / \U8d75\U5b66\U6d69";
id = 9776126;
image = "https://picx.zhimg.com/v2-00604b295890258d35108f32921dfdf2.jpg?source=8673f162";
"image_hue" = 0x42535e;
title = "\U300a\U5c01\U795e\U6f14\U4e49\U300b\U4e3a\U4ec0\U4e48\U6ca1\U6709\U5217\U5165\U56db\U5927\U540d\U8457\Uff1f";
type = 0;
url = "https://daily.zhihu.com/story/9776126";
},
{
"ga_prefix" = 102007;
hint = "\U4f5c\U8005 / \U7530\U53ef\U4e50";
id = 9776246;
image = "https://picx.zhimg.com/v2-520eb91c117bf9da4f62071961629b85.jpg?source=8673f162";
"image_hue" = 0xaa7246;
title = "\U5c0f\U4e8b \U00b7\U300c\U8c22\U8c22\Uff0c\U8fd9\U6b4c\U513f\U771f\U597d\U542c\Uff0c\U8c22\U8c22\U3002\U300d";
type = 0;
url = "https://daily.zhihu.com/story/9776246";
},
{
"ga_prefix" = 101907;
hint = "\U4f5c\U8005 / \U8d75\U6ce0";
id = 9776243;
image = "https://picx.zhimg.com/v2-e10faf6e06d42ddaae06fc8dc6e648b8.jpg?source=8673f162";
"image_hue" = 0x8e6238;
title = "\U4eba\U7c7b\U4ee5\U5916\U7684\U52a8\U7269\U6709\U6ca1\U6709\U628a\U81ea\U5df1\U7684\U98df\U7269\U9a6f\U5316\U5f97\U597d\U5403\U7684\U884c\U4e3a\Uff1f";
type = 0;
url = "https://daily.zhihu.com/story/9776243";
},
{
"ga_prefix" = 101807;
hint = "\U4f5c\U8005 / \U6731\U9526\U5e73";
id = 9776238;
image = "https://pic1.zhimg.com/v2-5ea4434e6ba5a4e1810059ae1c6c052e.jpg?source=8673f162";
"image_hue" = 0x1a1b37;
title = "\U9ed1\U6d1e\U5468\U56f4\U7684\U300c\U4e8b\U4ef6\U89c6\U754c\U300d\U662f\U4ec0\U4e48\Uff1f";
type = 0;
url = "https://daily.zhihu.com/story/9776238";
},
{
"ga_prefix" = 101707;
hint = "\U4f5c\U8005 / \U5357\U884c\U516e";
id = 9776232;
image = "https://picx.zhimg.com/v2-aaa227e7ccc5781303cc1d8e885b9768.jpg?source=8673f162";
"image_hue" = 0xb39e74;
title = "\U6211\U4e3a\U4ec0\U4e48\U603b\U89c9\U5f97\U8f9b\U5f03\U75be\U7528\U5178\U7684\U8bcd\U5199\U7684\U5f88\U4e00\U822c\Uff0c\U800c\U4e0d\U7528\U5178\U7684\U5199\U7684\U5f88\U597d\Uff1f";
type = 0;
url = "https://daily.zhihu.com/story/9776232";
}
);
}
model中包含其他model
仅需让一个model属性包含另一个model即可。
objectivec
// JSON
{
"memory ":{
"name":"lfc",
"birthday":"2023-07-26"
},
"name":"yl",
"age":17
}
// Model: 什么都不用做,转换会自动完成
@interface Memory : NSObject
@property NSString *name;
@property NSDate *birthday;
@end
@implementation Memory
@end
@interface People : NSObject
@property NSString *name;
@property NSUInteger age;
@property Author *author; //People 包含 Memory 属性
@end
@implementation People
@end
白名单与黑名单
注意:黑白名单不同时使用
objectivec
+ (NSArray<NSString *> *)modelPropertyBlacklist {
return @[@"Memory"];
}//这个方法不会处理JSON数据中的这个数据
+ (NSArray<NSString *> *)modelPropertyWhitelist {
return @[@"Memory"];
}//这个方法会让程序只处理JSON中的这个数据
总结
对YYModel的简单学习,后续还会对源码进行学习。