示例代码看最后。

跟不上时代的人突然间走在了时代的前列,果然有别样的风景。首先鄙视一下AFNetworking。这个东西实在太难用了。不想封装都不行,要不写一大堆代码。

NSURL *URL = [NSURL URLWithString:@"http://example.com/resources/123.json"];
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就简单的很多了,如:

Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]) .response { request, response, data, error inprint(response) }

都是一个GET请求,但是可见的是Alamofire代码量少很多。这也是和AFNetworking3.x比较了,如果你用的是AFNetworking2.x的话代码量的对比更加明显。对于程序员来说调用方法的API简单方便就是用户体验。Developer们也是需要满足UE的需要的。

下面开始进入正题。下面用请求微博的time line来做栗子。

parameters = ["access_token": weiboUserInfo.accessToken ?? "",  "source": ConstantUtil.WEIBO_APPKEY] //1
Alamofire.request(.GET, "https://api.weibo.com/2/statuses/friends_timeline.json" //2, parameters: parameters, encoding: .URL, headers: nil).responseString(completionHandler: {response inprint("response:- \(response)") //3
})

这里用Alamofire请求微博的time line。

  1. 请求微博的time line就需要SSO或者网页方式登录微博之后从服务器返回的access_token。另外一个必须的输入参数就是添加微博应用的时候生成的app key。

  2. https://api.weibo.com/2/statu...请求的url。
    这个url返回的就是你follow的好友的微博。就是你一打开微博客户端看到的那些。

  3. 我们知道Alamofire可以把请求返回的数据转化为JSON、String和NSData。如果是作为JSON来处理,也就是使用了responseJSON 方法的话,JSON数据会被自动转化为NSDictionary。我们后面需要用到字符串来实现json字符串和Model对象的匹配,所以我们用方法responseString

如果一切设置正确,你会看到这样的结果:

{"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": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。","url": "http://blog.sina.com.cn/zaku","profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1","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的解析都是从外往内进行的,这个层层解析的过程中一般没有特殊指定的话每一层都不能少(可以通过制定解析路径减少)。每一层都需要配备一个实体类。

最外面的一层是:

{"statuses": [...],"previous_cursor": 0,      "next_cursor": 11488013766,     "total_number": 81655
}

所以对应的model定义是这样的:

import ObjectMapperclass BaseModel: Mappable {  // 1var previousCursor: Int?var nextCursor: Int?//var statuses var totalNumber: Int?required init?(_ map: Map) {  // 2}func mapping(map: Map) { // 3previousCursor <- map["previous_cursor"]nextCursor <- map["next_cursor"]//hasVisible <- map["hasvisible"]statuses <- map["..."] // 4totalNumber <- map["total_number"]}
}

最重要的是先import ObjectMapper。没有这个什么都干不了。

  1. BaseModel类需要实现Mappable接口。后面就是这个protocol的实现。

  2. 返回可能为空对象的初始化方法,法暂时用不到。

  3. 这个方法最关键了。在这个方法里指定json的值对应的是model里的哪个属性。这部分功能可以自动实现,哪位有心人可以fork出来写一个,也方便大家使用

  4. 请看下文。

在深入一层

上问的标签4的内容我们在这里详细介绍。我们要展示的内容都是在statuses下的。那么我们应该如何处理这部分的内容呢?statuses的json格式是这样的:

{"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可以这样写:

class BaseModel {var text: String?required init?(_ map: Map) { }func mapping(map: Map) {self.text <- map["statuses.text"]}
}

但是这样是错误的!因为statuses是一个数组,而不是一个对象。只有statuses对应的是一个对象的时候才适用于这个情况。

对上面的代码进行修改,让其适用于数据的情况。

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应该是已经露馅了。

class StatusModel: BaseModel { // 1var 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) // 2statusId <- map["id"]thumbnailPic <- map["thumbnail_pic"]bmiddlePic <- map["bmiddle_pic"]originalPic <- map["original_pic"]weiboText <- map["text"]}
}
  1. 也就是我们说的json对象嵌套时的model类的继承关系。

  2. 在这种继承关系中需要十分注意的是。在Mappable协议的方法的调用中需要先调用基类的对应方法,super.init(map)super.mapping(map)。至于说mapping 方法的映射关系,每个json对象对应的model类只管这一个对象的就可以。

那么在最外层的BaseModel类中的statuses属性也就可以给出一个正确的完整的写法了。

class BaseModel: Mappable {var previousCursor: Int?var nextCursor: Int?var hasVisible: Bool?var statuses: [StatusModel]? // 1var totalNumber: Int?required init?(_ map: Map) {}func mapping(map: Map) {previousCursor <- map["previous_cursor"]nextCursor <- map["next_cursor"]hasVisible <- map["hasvisible"]statuses <- map["statuses"]  // 2totalNumber <- map["total_number"]}
}
  1. 内层的statuses数组直接调用内层json对象对应的model类的数组,也即是 var statuses: [StatusModel]?

  2. mapping方法中指定属性和json对象的关系,这里是statuses <- map["statuses"]

这样ObjectMapper就知道应该如何解析json字符串到对应的类对象中了。除了上面提到的,ObjectMapper还有很多其他的功能。如果需要了解更多可以查看官方文档。

那么从http请求,到返回数据,到解析json串的一系列动作就可以完整的联结起来了。最开始介绍使用Alamofire请求并成功返回之后,我们只是把字符串打印了出来。现在可以调用map方法来匹配json串和我们定义好的model类了。

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 inprint("response:- \(response)") let statuses = Mapper<BaseModel>().map(response.result.value) // 1print("total number: \(statuses!.totalNumber)")if let timeLine = statuses where timeLine.totalNumber > 0 { // 2self.timeLineStatus = timeLine.statusesself.collectionView?.reloadData()}})
  1. 使用Mapper<BaseModel>().map(response.result.value)方法来映射json串。这里需要分开来看。Mapper<BaseModel>()初始化了一个Mapper对象。Mapper是一个泛型,类型参数就是我们定义的最外层的json对象对应的model类BaseModel。之后我们调用了这个初始化好的Mapper对象的map方法。这个方法的参数就是一个json串,也就是字符串类型的,但是这个字符串必须是json格式的。response.result.value取出了http请求之后返回的json串。

  2. map方法返回的是可空类型的。所以需要用if-let的方式检查一下返回的值是否可用。在可用的情况下用where语句判断返回的timeLine总数是否大于零。大于零才是有意义的,才刷新collection view。

示例代码在这里。这里没有使用微博的API,而是用了Github的API来演示请求和JSON处理。比较简单。不过Github奇葩的返回的结果就是一个JSON Array,居然可以使用ObjectMapper的mapArray方法一次搞定。这算是一个小坑。其他的都很常规了。

to be continued...

Swift: 用Alamofire做http请求,用ObjectMapper解析JSON相关推荐

  1. go 发送http请求; Golang 解析JSON 篇

    https://www.runoob.com/go/go-fmt-sprintf.html go 发送http请求: package mainimport ("io/ioutil" ...

  2. 二、用ObjectMapper解析json格式

  3. Swift 网络请求数据与解析

    一: Swift 网络数据请求与处理最常用第三方 又有时间出来装天才了,还是在学swift,从中又发现一些问题,这两天上网找博客看问题弄的真的心都累.博客一篇写出来,好多就直接照抄,就没有实质性的把问 ...

  4. IOS15之swift的Alamofire 5.4框架的网络封装

    IOS15之swift的Alamofire 5.4框架的网络封装 此Alamofire 版本较高,是基于IOS15 和最新的 Alamofire 5.4.4 版本,截止我发稿的时候,最新版本,网上其他 ...

  5. Swift 掌控Moya的网络请求、数据解析与缓存

    Moya 在Swift开发中起着重要的网络交互作用,但是还有不如之处,比如网络不可用时,返回的 Response 为 nil,这时还得去解析相应的 Error Codable 可以帮助我们快速的解析数 ...

  6. python 使用 requests 做 http 请求

    1. get import requests# 最简单的get请求 r = requests.get(url) print(r.status_code) print(r.json())# url 中? ...

  7. spock做post请求get请求,在springboot环境下使用gradle构建工具的demo,IDEA的开发工具

    1.创建一个springboot项目,基于gradle的创建 1)new一个project 2)选择spring initializr 3)选择gradle project,然后next 4)选择一个 ...

  8. 用Alamofire进行网络请求的一段代码解析(一)

    //AnyObject:json //Mark:利用alamofire 发送网络请求,并返回数据json:AnyObject,需要强制转换为NSDictionary字典类型. /* 向服务器发送请求: ...

  9. 如何用curl做PUT请求?

    本文翻译自:How to do a PUT request with curl? 如何使用curl测试RESTful PUT(或DELETE)方法? #1楼 参考:https://stackoom.c ...

最新文章

  1. Excel弱爆了!这个工具30分钟完成了我一天的工作量,零基础、文科生也能学!...
  2. C++又一坑:动态链接库中的全局变量
  3. 【技术干货】TC基础与自动化
  4. 清晨给研究生改论文改到“火大”
  5. java 友好时间显示_仿微信的IM聊天时间显示格式(含iOS/Android/Web实现)[图文+源码]...
  6. iatf16949内审员_申请IATF16949认证有什么要求
  7. 常用的分隔符有哪三种_Node.js系列四 - 常用的内置模块
  8. 第六届蓝桥杯试题c/c++B组5
  9. Oracle和sqlserver数据类型对应
  10. Redis进程异常退出排查
  11. java图片旋转90度_Java实现图片内容无损任意角度旋转
  12. Linux下mysql数据恢复
  13. 从ResNet101到ResNet50
  14. HP LaserJet 1010 安装方法
  15. Linux—添加开机启动
  16. BZOJ2069 POI2004ZAW(最短路)
  17. WPS:将彻底关闭广告
  18. 判断两个整数是否互质
  19. 同态加密能否拯救云计算
  20. android studio 调试问题解决记录

热门文章

  1. 【学术快报】韩世辉课题组在《eLife》发表论文揭示群体冲突中复仇的神经生物学机制...
  2. 国际机器人联合会:全球工业机器人2019报告
  3. 联合国发布AI报告:自动化和AI对亚洲有巨大影响【附报告下载】
  4. 阿里商业白皮书:每个企业都要变成一个数据公司
  5. 2018全球技术展望报告
  6. 雷克世界:Gyrfalcon加入芯片角斗场,又一款改变AI界的产品问世
  7. Vim 项目重要维护者去世,Vim 之父以 Vim 9 悼念挚友
  8. Django REST framework 分页
  9. 如何在数据库中高效实现订座功能?
  10. webstorm更改scss输出路径