IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【iOS】JSONModel的基本使用 -> 正文阅读

[移动开发]【iOS】JSONModel的基本使用

什么是JSONModel?

  • 做移动端开发,解析网络数据是必不可少的工作之一。iOS原生框架很早前就已经提供了将JSON数据直接映射成数组或者字典对象的方法,并且结合KVC,也可以将字典数据直接赋值给对象。但是这种方式十分不灵活,例如如果网络数据中的字段与我们数据模型中的字段不一致,某些网络数据的字段可能为nil等等都需要开发者单独的处理。使用JSOMModel可以十分方便的处理映射过程中的各种情况。

越来越多的移动应用更倾向于用JSON这种数据格式。一旦计划开发移动应用的并有与后台通信的需求,则要用JSON数据格式与服务器通信互相通信

  • JSONModel是用Objective-C写的开源库。它包含了接受发送解析JSON数据,用JSON数据驱动初始化你的类,还能够检验JSON和嵌套模型等功能。

核心数据模型类JSONModel

  • 平时在使用JSOMModel框架时,往往只会用到JSOMModel这一个类。JSONModel框架中最核心的类是JSONModel类,其中代码大约有1400行。首先,其头文件中声明了几个协议,如下:
@protocol Index
@end
@protocol Ignore
@end
@protocol Optional
@end
  • 需要注意,这些协议里面都没有约定任何方法,它们也不会用来实现的,其作为属性的一种标记,例如将属性添加Ignore协议,则JSONModel不会对这个属性进行解析、使用这种方式来进行本地数据的管理,例如:
@interface MyOnject : JSONModel

@property(nonatomic, strong) NSString * firstName;

@property(nonatomic, strong) NSString * lastName;
//这个属性是本地拼接 使用
@property(nonatomic, strong) NSString<Ignore> * fullName;

@end
  • Optional协议表示这个属性是可选的,即JSON数据中如果有这个属性就解析,如果没有就跳过。
    a. 某些属性值可以为空;
    b. 防止由于服务器返回数据为空导致JSONModel异常(程序崩溃);
  • Index协议标记这个属性是当前对象的主键,已经弃用
  • 有了这3个协议,在声明属性时,我们可以十分容易的设定他们的解析规则,在JSONModel中,协议除了可以用来规定解析规则外,还可以用来指定自定义数据类型的解析,只是我们需要自己定义一个协议,名称与自定义类名一致,示例如下:
#import "JSONModel.h"

@protocol Address
@end


@interface Address:JSONModel

@property(nonatomic, strong) NSString * info;

@end


@interface MyObject : JSONModel

@property(nonatomic, strong) NSArray<Address> * address;

@end
  • 如上代码所示,在解析数据时,会直接将address数组中赋值为Address的对象

JSON的一些基本使用

JSON转化为模型

//JSON
{   "country": "Germany", 
	"dialCode": 49, 
	"isInEurope": true 
}

//Model
#import "JSONModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface CountryModel : JSONModel

@property (nonatomic, copy) NSString *country;
@property (nonatomic, copy) NSString *dialCode;
@property (nonatomic, assign) BOOL isInEurope;

@end

NS_ASSUME_NONNULL_END

//JSON转换为模型
NSError *error;
CountryModel *countryModel = [[CountryModel alloc] initWithDictionary:dic error:&error];

模型转换为字典

//将模型快速转换为字典
NSDictionary *dict = [countryModel toDictionary];

模型转换为字符串

//将模型快速转换为字符串
NSString *string = [countryModel toJSONString];

设置所有属性可选(所有属性值可以为空)

a. Model 的所有属性值可以为空;
b. 防止由于服务器数据返回空导致JSONModel异常(程序崩溃);
c. 官方建议尽量避免使用该方法(即使要全部属性为可选,也尽量是在每个属性那里标注为Optional);

eg: 
@implementation TestModel
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
    return YES;
}
@end

对于集合、嵌套型数据

例如下面:

{
    "date":"20211011",
    "stories":[
        {
            "image_hue":"0x555555",
            "title":"出现低落焦虑时,怎么分辨是「短暂情绪」还是生病了?",
            "url":"https:\/\/daily.zhihu.com\/story\/9741137",
            "hint":"精神科医生宋崇升 · 4 分钟阅读",
            "ga_prefix":"101107",
            "images":[
                "https:\/\/pic3.zhimg.com\/v2-e68e99fafc8f87cd3c91a17a6f835d1f.jpg?source=8673f162"
            ],
            "type":0,
            "id":9741137
        },
        Object{...},
        Object{...},
        Object{...},
        Object{...},
        Object{...}
    ],
    "top_stories":[
        {
            "image_hue":"0xb38d51",
            "hint":"作者 \/ 男爵兔",
            "url":"https:\/\/daily.zhihu.com\/story\/9741077",
            "image":"https:\/\/pica.zhimg.com\/v2-ca0fe2412807776234bf0019f7276541.jpg?source=8673f162",
            "title":"2021 年诺贝尔文学奖授予小说家阿卜杜勒拉扎克·古尔纳,他是谁?",
            "ga_prefix":"100807",
            "type":0,
            "id":9741077
        },
        Object{...},
        Object{...},
        Object{...},
        Object{...}
    ]
}

  • 这次的数据很复杂他有嵌套, 有数组,我们应该怎样处理这种嵌套模型呢?我们应该对每一个要嵌套的都写成一个类,但并不是意味着要写成多个类文件,而是只需要在一个类文件里把该有的写好就行 如下代码:
@protocol StoriesModel
@end

@protocol Top_StoriesModel
@end

#import "JSONModel.h"

NS_ASSUME_NONNULL_BEGIN
@interface StoriesModel : JSONModel
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *ga_prefix;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *image_hue;
@property (nonatomic, copy) NSString *id;
@end

@interface Top_StoriesModel : JSONModel
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *ga_prefix;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *image_hue;
@property (nonatomic, copy) NSString *id;
@end

@interface TestModel : JSONModel
@property (nonatomic, copy) NSString *date;
@property (nonatomic, copy) NSArray<StoriesModel>* stories;
@property (nonatomic, copy) NSArray<Top_StoriesModel>* top_stories;

@end

NS_ASSUME_NONNULL_END

设置下划线自动转驼峰

  • 自定义把下划线字段解析为驼峰命名属性
  • 场景:服务器数据返回下划线命名字段可为Model中以驼峰命名的属性相应的赋值
  • mapperFromUpperCaseToLowerCase 大写转小写
 {
   "order_id": 104,
   "order_product" : @"Product#1",
   "order_price" : 12.95
 }

@interface OrderModel : BaseModel
@property (nonatomic, strong) NSString *orderId;
@property (nonatomic, assign) float     orderPrice;
@property (nonatomic, strong) NSString *orderProduct;

@end

@implementation OrderModel

+ (JSONKeyMapper *)keyMapper {
    return [JSONKeyMapper mapperFromUnderscoreCaseToCamelCase];
}

@end

实例解析

  • 首先要导入JSONModel库,与Masonry库的导入相同,修改库名即可
  • 创建一个TestModel类,该类继承于JSONModel
  • 将请求到的json的数据在 .h 文件中声明为属性。因为涉及到数据的嵌套,因此用到上面所用到的方法,对每一个要嵌套的都写成一个类,把写好的类放在该类文件里
@protocol StoriesModel
@end

@protocol Top_StoriesModel
@end

#import "JSONModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface StoriesModel : JSONModel
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *ga_prefix;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *image_hue;
@property (nonatomic, copy) NSString *id;
@end

@interface Top_StoriesModel : JSONModel
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *ga_prefix;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *image_hue;
@property (nonatomic, copy) NSString *id;
@end

@interface TestModel : JSONModel
@property (nonatomic, copy) NSString *date;
@property (nonatomic, copy) NSArray<StoriesModel> *stories;
@property (nonatomic, copy) NSArray<Top_StoriesModel> *top_stories;
@end

NS_ASSUME_NONNULL_END

TestModel.m文件中一般不需要做其他事,但是为了防止由于服务器数据返回空导致JSONModel异常(程序崩溃),所以在 .m 中添加如下方法函数

#import "TestModel.h"

@implementation Top_StoriesModel

+ (BOOL)propertyIsOptional:(NSString *)propertyName {
    return YES;
}
@end

@implementation StoriesModel
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
    return YES;
}
@end

@implementation TestModel
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
    return YES;
}

@end
  • 此时解析的流程基本完成,剩下就是将数据通过网络请求传过来,并将model初始化,如下
- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *json = @"http://news-at.zhihu.com/api/4/news/latest";
        json = [json stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        NSURL *testUrl = [NSURL URLWithString:json];
        NSURLRequest *testRequest = [NSURLRequest requestWithURL:testUrl];
        NSURLSession *testSession = [NSURLSession sharedSession];
        NSURLSessionDataTask *testDataTask = [testSession dataTaskWithRequest:testRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            TestModel *country = [[TestModel alloc] initWithData:data error:nil];
             NSLog(@"%@",country.stories[0]);
            
        }];
        //任务启动
        [testDataTask resume];
}
  • 如果传过来的 JSON 合法,你所定义的所有的属性都会与该 JSON 值相匹配,并且 JSONModel 也会尝试尽可能的转换成你所想要的数据

此时输出如下:

遇到的问题

  1. 写完如上代码后网络请求时会报错,如下

请添加图片描述

  • 原因如下:

iOS9引入了新特性:App Transport Security (ATS),新特性要求App内访问的网络必须使用HTTPS协议。

但是现在公司的项目使用的是HTTP协议,使用私有加密方式保证数据安全。现在也不能马上改成HTTPS协议传输。

  • 解决方案:

Info.plist中添加如下后即可正常进行网络请求了
请添加图片描述

  1. 如果我想在viewDidLoad中获取嵌套数组中的元素,例如:
NSLog(@"%@",country.stories[0].title);
  • 此时不能直接进行打印,因为在该文件中我们没有事先声明,此处是model嵌套model,所以声明一下即可
@property (nonatomic, copy) StoriesModel *stories;
  • 将访问到的country.stories[0]赋给刚才声明的属性,因为是在block中进行的操作,所以不能直接使用_stories = country.stories[0];

请添加图片描述

  • 在代码中使用_stories时,编译器将用self->_stories替换代码,并且如果在块内使用它,则该块将捕获self自身而不是stories本身。 警告只是为了确保开发人员了解此行为。
	self->_stories = country.stories[0];
    NSLog(@"%@",self->_stories.title);
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-15 11:54:32  更:2021-10-15 11:55:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:57:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码