Swift: Alamofire -> http请求 & ObjectMapper -> 解析JSON
|
1
2
3
4
5
6
7
8
9
10
11
|
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];[manager GET:URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) { NSLog(@"JSON: %@", responseObject); } failure:^(NSURLSessionTask *operation, NSError *error) { NSLog(@"Error: %@", error); }]; |
Http请求
但是用alamofire就简单的很多了,如:
|
1
2
3
4
|
.response { request, response, data, error in print(response) } |
都是一个GET请求,但是可见的是Alamofire代码量少很多。这也是和AFNetworking3.x比较了,如果你用的是AFNetworking2.x的话代码量的对比更加明显。对于程序员来说调用方法的API简单方便就是用户体验。Developer们也是需要满足UE的需要的。
下面开始进入正题。下面用请求微博的time line来做栗子。
|
1
2
3
4
5
6
|
parameters = ["access_token": weiboUserInfo.accessToken ?? "", "source": ConstantUtil.WEIBO_APPKEY] //1 , parameters: parameters, encoding: .URL, headers: nil) .responseString(completionHandler: {response in print("response:- \(response)") //3}) |
这里用Alamofire请求微博的time line。
1. 请求微博的time line就需要SSO或者网页方式登录微博之后从服务器返回的access_token。另外一个必须的输入参数就是添加微博应用的时候生成的app key。
2. https://api.weibo.com/2/statuses/friends_timeline.json请求的url。
这个url返回的就是你follow的好友的微博。就是你一打开微博客户端看到的那些。
3. 我们知道Alamofire可以把请求返回的数据转化为JSON、String和NSData。如果是作为JSON来处理,也就是使用了responseJSON方法的话,JSON数据会被自动转化为NSDictionary。我们后面需要用到字符串来实现json字符串和Model对象的匹配,所以我们用方法responseString。
如果一切设置正确,你会看到这样的结果:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
{ "statuses": [ { "created_at": "Tue May 31 17:46:55 +0800 2011", "id": 11488058246, "text": "求关注。", "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>", "favorited": false, "truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in_reply_to_screen_name": "", "geo": null, "mid": "5612814510546515491", "reposts_count": 8, "comments_count": 9, "annotations": [], "user": { "id": 1404376560, "screen_name": "zaku", "name": "zaku", "province": "11", "city": "5", "location": "北京 朝阳区", "description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。", "domain": "zaku", "gender": "m", "followers_count": 1204, ... } }, ... ], "ad": [ { "id": 3366614911586452, "mark": "AB21321XDFJJK" }, ... ], "previous_cursor": 0, // 暂时不支持 "next_cursor": 11488013766, // 暂时不支持 "total_number": 81655} |
以上是微博给出来的例子的一部分,我们来看看我们需要什么。我们需要一部分文字和一部分的图片。之后要显示的内容主要就是文字或者图片。
解析
我们用ObjectMapper解析json。ObjectMapper是一个双向的转化工具。可以把json字符串转化成model也可以把model转化成json字符串。
安装ObjectMapper:
pod 'ObjectMapper', '~> 1.1'
ObjectMapper对于json的解析都是从外往内进行的,这个层层解析的过程中一般没有特殊指定的话每一层都不能少(可以通过制定解析路径减少)。每一层都需要配备一个实体类。
最外面的一层是:
|
1
2
3
4
5
6
7
8
|
{ "statuses": [ ... ], "previous_cursor": 0, "next_cursor": 11488013766, "total_number": 81655} |
所以对应的model定义是这样的:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import ObjectMapperclass BaseModel: Mappable { // 1 var previousCursor: Int? var nextCursor: Int? //var statuses var totalNumber: Int? required init?(_ map: Map) { // 2 } func mapping(map: Map) { // 3 previousCursor <- map["previous_cursor"] nextCursor <- map["next_cursor"] //hasVisible <- map["hasvisible"] statuses <- map["..."] // 4 totalNumber <- map["total_number"] }} |
最重要的是先import ObjectMapper。没有这个什么都干不了。
1. BaseModel类需要实现Mappable接口。后面就是这个protocol的实现。
2. 返回可能为空对象的初始化方法,法暂时用不到。
3. 这个方法最关键了。在这个方法里指定json的值对应的是model里的哪个属性。这部分功能可以自动实现,哪位有心人可以fork出来写一个,也方便大家使用。
4. 请看下文。
在深入一层
上问的标签4的内容我们在这里详细介绍。我们要展示的内容都是在statuses下的。那么我们应该如何处理这部分的内容呢?statuses的json格式是这样的:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
{ "statuses": [ { "created_at": "Tue May 31 17:46:55 +0800 2011", "id": 11488058246, "text": "求关注。", "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>", "favorited": false, "truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in_reply_to_screen_name": "", "geo": null, ... } ],} |
可以有两个方式来处理深层的json数据。一个是在mapping方法里指定json数据和属性的对应关系。比如在BaseMode类中映射statuses中的text可以这样写:
|
1
2
3
4
5
6
7
8
9
10
|
class BaseModel { var text: String? required init?(_ map: Map) { } func mapping(map: Map) { self.text <- map["statuses.text"] }} |
但是这样是错误的!因为statuses是一个数组,而不是一个对象。只有statuses对应的是一个对象的时候才适用于这个情况。
对上面的代码进行修改,让其适用于数据的情况。
|
1
2
3
4
5
6
7
8
9
10
|
class BaseModel { var text: String? required init?(_ map: Map) { } func mapping(map: Map) { self.text <- map["status.0.text"] }} |
self.text <- map["statuses.0.text"]中间的数字零说明text属性对应的是json中的statuses数组的第一个元素的text的值。但是在statuses下会有很多个json对象,一个一个的挨个解析的方式显然是不适合的。更不用说这才两层,有多少奇葩的API返回的是三层甚至更多的?
那么就剩下最后的一种方法了。内层json的model类继承外层的json的model类。按照这个方法那么我们为statuses对应的json对象定义一个model类为StatusModel。由于StatusModel对应的是内层的json对象,那么就需要继承外层的json对象的类,也就是BaseModel。刚开始就命名为BaseModel应该是已经露馅了。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class StatusModel: BaseModel { // 1 var statusId: String? var thumbnailPic: String? var bmiddlePic: String? var originalPic: String? var weiboText: String? var user: WBUserModel? required init?(_ map: Map) { super.init(map) // 2 } override func mapping(map: Map) { super.mapping(map) // 2 statusId <- map["id"] thumbnailPic <- map["thumbnail_pic"] bmiddlePic <- map["bmiddle_pic"] originalPic <- map["original_pic"] weiboText <- map["text"] }} |
- 也就是我们说的json对象嵌套时的model类的继承关系。
- 在这种继承关系中需要十分注意的是。在
Mappable协议的方法的调用中需要先调用基类的对应方法,super.init(map)和super.mapping(map)。至于说mapping方法的映射关系,每个json对象对应的model类只管这一个对象的就可以。
那么在最外层的BaseModel类中的statuses属性也就可以给出一个正确的完整的写法了。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class BaseModel: Mappable { var previousCursor: Int? var nextCursor: Int? var hasVisible: Bool? var statuses: [StatusModel]? // 1 var totalNumber: Int? required init?(_ map: Map) { } func mapping(map: Map) { previousCursor <- map["previous_cursor"] nextCursor <- map["next_cursor"] hasVisible <- map["hasvisible"] statuses <- map["statuses"] // 2 totalNumber <- map["total_number"] }} |
- 内层的statuses数组直接调用内层json对象对应的model类的数组,也即是
var statuses: [StatusModel]?。 - 在
mapping方法中指定属性和json对象的关系,这里是statuses <- map["statuses"]。
这样ObjectMapper就知道应该如何解析json字符串到对应的类对象中了。除了上面提到的,ObjectMapper还有很多其他的功能。如果需要了解更多可以查看官方文档。
或者是另外一种 方法二:
StatusModel 不一定一定得继承自基类Model ,这需要看是否有继承的需要(即是否包含相同字段)
如果不是继承的关系: (mapping 写法)
mutating func mapping(map: ObjectMapper.Map) {
//blabla ...
// settingDisplay <- map["settingDisplayList"]
//settingItem <- map["settingItemList"]
}
或者是另外一种 方法三:
如果是继承关系: //外层的类是这样写 (mapping 写法)
override func mapping(map: ObjectMapper.Map) {
super.mapping(map)
// blabla
}
基类里面像这样写:
static func objectForMapping(map: Map) -> Mappable? {
if let type = map["recordType"].currentValue as? String {
switch type {
case "communicationNotebook":
return CommunicationNotebookModel(map)
case "dailyReport":
return DailyReportModel(map)
case "photo":
return RecordPhotoModel(map)
case "meal":
return MealModel(map)
case "excretion":
return ExcretionModel(map)
case "moisture":
return MoistureModel(map)
case "snack":
return SnackModel(map)
case "vital":
return VitalModel(map)
case "drug":
return DrugModel(map)
case "sleep":
return SleepModel(map)
case "bathing":
return BathingModel(map)
case "recreation":
return RecreationModel(map)
case "outing":
return OutingModel(map)
case "study":
return StudyModel(map)
default:
return nil
}
}
return nil
}
}
外层的继承类像这样写:
class CommunicationNotebookModel: RecordItemModel { //内层json的model类继承外层的json的model类
/**
内容
*/
var content: String?
var remarks: String?
override func mapping(map: ObjectMapper.Map) {
super.mapping(map) //在Mappable协议的方法的调用中需要先调用基类的对应方法,super.init(map)和super.mapping(map)
content <- map["content"]
remarks <- map["remarks"]
}
}
那么从http请求,到返回数据,到解析json串的一系列动作就可以完整的联结起来了。最开始介绍使用Alamofire请求并成功返回之后,我们只是把字符串打印了出来。现在可以调用map方法来匹配json串和我们定义好的model类了。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
parameters = ["access_token": weiboUserInfo.accessToken ?? "", "source": ConstantUtil.WEIBO_APPKEY] Alamofire.request(.GET, "https://api.weibo.com/2/statuses/friends_timeline.json", parameters: parameters, encoding: .URL, headers: nil) .responseString(completionHandler: {response in print("response:- \(response)") let statuses = Mapper<BaseModel>().map(response.result.value) // 1 print("total number: \(statuses!.totalNumber)") if let timeLine = statuses where timeLine.totalNumber > 0 { // 2 self.timeLineStatus = timeLine.statuses self.collectionView?.reloadData() } }) |
- 使用
Mapper<BaseModel>().map(response.result.value)方法来映射json串。这里需要分开来看。Mapper<BaseModel>()初始化了一个Mapper对象。Mapper是一个泛型,类型参数就是我们定义的最外层的json对象对应的model类BaseModel。之后我们调用了这个初始化好的Mapper对象的map方法。这个方法的参数就是一个json串,也就是字符串类型的,但是这个字符串必须是json格式的。response.result.value取出了http请求之后返回的json串。 map方法返回的是可空类型的。所以需要用if-let的方式检查一下返回的值是否可用。在可用的情况下用where语句判断返回的timeLine总数是否大于零。大于零才是有意义的,才刷新collection view
参考链接:http://www.cnblogs.com/sunshine-anycall/p/5170372.html
Swift: Alamofire -> http请求 & ObjectMapper -> 解析JSON的更多相关文章
- Swift: 用Alamofire做http请求,用ObjectMapper解析JSON
跟不上时代的人突然间走在了时代的前列,果然有别样的风景.首先鄙视一下AFNetworking.这个东西实在太难用了.不想封装都不行,要不写一大堆代码. NSURL *URL = [NSURL URLW ...
- iapp,iapp http请求,iapp解析json数据
iapp发送http请求,并解析json数据 //http操作 t() { s a = "http://wap.baidu.com/" //目标url hs(a, null, nu ...
- autojs,autojs 发送http请求,autojs 解析json数据
如题,我这个就直接上代码吧 (function () { let request = http.request; // 覆盖http关键函数request,其他http返回最终会调用这个函数 http ...
- [Swift]SwiftyJSON的使用:解析JSON
用法 初始化Initialization import SwiftyJSON let json = JSON(data: dataFromNetworking) 或者 let json = JSON( ...
- body-parser Node.js(Express) HTTP请求体解析中间件
body-parser Node.js(Express) HTTP请求体解析中间件 2016年06月08日 781 声明 在HTTP请求中,POST.PUT和PATCH三种请求方法中包 ...
- 在线聊天项目1.4版 使用Gson方法解析Json字符串以便重构request和response的各种请求和响应 解决聊天不畅问题 Gson包下载地址
在线聊天项目结构图: 多用户登陆效果图: 多用户聊天效果图: 数据库效果图: 重新构建了Server类,使用了Gson方法,通过解析Json字符串,增加Info类,简化判断过程. Server类代码如 ...
- 阶段一:通过网络请求,获得并解析JSON数据(天气应用)
“阶段一”是指我第一次系统地学习Android开发.这主要是对我的学习过程作个记录. 在上一篇阶段一:解析JSON中提到,最近在写一个很简单的天气预报应用.即使功能很简单,但我还是想把它做成一个相对完 ...
- 使用jQuery解析JSON数据(由ajax发送请求到php文件处理数据返回json数据,然后解析json写入html中呈现)
在上一篇的Struts2之ajax初析中,我们得到了comments对象的JSON数据,在本篇中,我们将使用jQuery进行数据解析. 我们先以解析上例中的comments对象的JSON数据为例,然后 ...
- 异步POST请求解析JSON
异步POST请求解析JSON 一.创建URL NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/order ...
随机推荐
- Windows系统顽固文件删除方法
con nul都是windows的设备,默认是不允许删除的,如果你一定要删除,可以按照以下方法进行删除!新建一个记事本输入一下内容(直接复制即可)DEL /F /A /Q \\?\%1 RD /S / ...
- IOS 类的属性修饰符atomic
在声明一个类的属性时,默认这个属性会被修饰atomic,意思是原子性访问的. nonatomic和atomic修饰的属性,在自己没有重写setter和getter的时候才会发生作用,其主要的作用可以理 ...
- Rancher安装使用
官网 http://docs.rancher.com/rancher/latest/en/quick-start-guide/#add-hosts 安装步骤: 1 Start up a Linux m ...
- .Net Core 中使用AutoMapper
1.新建一个类 using AutoMapper; using YourModels; using YourViewModels; namespace YourNamespace { public c ...
- FZU 1920 Left Mouse Button 简单搜索
题意就是扫雷 问最少多少次可以把图点开…… 思路也很明显 就是先把所有的标记一遍 就当所有的都要点…… 录入图…… 所有雷都不标记…… 之后呢 遍历图…… 然后碰到0就搜索一圈 碰到数字就标记…… 不 ...
- 关于jquery选择器中:first和:first-child和:first-of-type的区别及:nth-child()和:nth-of-type()的区别
:first:选择第一个出现符合的元素 :first-child:选择限制条件中的第一个元素,并且必须和冒号前面的标签一致 :first-of-type:选择所有限制条件下的第一个冒号前面的标签元素, ...
- 推荐两个好用的Xcode插件(提供下载链接)
这里推荐两款好用的Xcode插件,并提供下载链接. 一.插件和使用如下: 1.两款插件 对项目中图片提供自动提示功能的插件:KSImageNamed-Xcode-master 提供快速创建自动注释:V ...
- .net大型分布式电子商务架构说明(转载来自<头条>)
背景 构建具备高可用,高扩展性,高性能,能承载高并发,大流量的分布式电子商务平台,支持用户,订单,采购,物流,配送,财务等多个项目的协作,便于后续运营报表,分析,便于运维及监控. 架构演变 基础框架剥 ...
- erlang四大behaviour之三-gen_event
来源:http://www.cnblogs.com/puputu/articles/1689623.html 1. 事件处理规则 在OTP中,事件管理器是一个事件可以发送到的命名对象,一个事件可以是一 ...
- 生成SQL脚本的方法
2点需要注意的关键: (1)选择特定数据库对象不包含用户选项: (2)要编写脚本的数据的类型选择"架构和数据".