Swift: Alamofire -> http请求 & ObjectMapper -> 解析JSON


1

2

3

4

5

6

7

8

9

10

11

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就简单的很多了,如:


1

2

3

4

Alamofire.request(.GET"https://httpbin.org/get"parameters: ["foo""bar"])

    .response requestresponsedataerror 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

Alamofire.request(.GET"https://api.weibo.com/2/statuses/friends_timeline.json" //2

    parametersparametersencoding: .URLheadersnil)

    .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""人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。",

                "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的解析都是从外往内进行的,这个层层解析的过程中一般没有特殊指定的话每一层都不能少(可以通过制定解析路径减少)。每一层都需要配备一个实体类。

最外面的一层是:


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 ObjectMapper

class BaseModelMappable {  // 1

    var previousCursorInt?

    var nextCursorInt?

    //var statuses

    var totalNumberInt?

    required init?(_ mapMap) {  // 2

    }

    func mapping(mapMap) { // 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 textString?

  required init?(_ mapMap) {

  }

  func mapping(mapMap) {

    self.text <map["statuses.text"]

  }

}

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

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


1

2

3

4

5

6

7

8

9

10

class BaseModel {

  var textString?

  required init?(_ mapMap) {

  }

  func mapping(mapMap) {

    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 StatusModelBaseModel // 1

    var statusIdString?

    var thumbnailPicString?

    var bmiddlePicString?

    var originalPicString?

    var weiboTextString?

    var userWBUserModel?

    required init?(_ mapMap) {

        super.init(map)  // 2

    }

    override func mapping(mapMap) {

        super.mapping(map// 2

        statusId <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属性也就可以给出一个正确的完整的写法了。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

class BaseModelMappable {

    var previousCursorInt?

    var nextCursorInt?

    var hasVisibleBool?

    var statuses: [StatusModel]? // 1

    var totalNumberInt?

    required init?(_ mapMap) {

    }

    func mapping(mapMap) {

        previousCursor <map["previous_cursor"]

        nextCursor <map["next_cursor"]

        hasVisible <map["hasvisible"]

        statuses <map["statuses"]  // 2

        totalNumber <map["total_number"]

    }

}

  1. 内层的statuses数组直接调用内层json对象对应的model类的数组,也即是var statuses: [StatusModel]?
  2. mapping方法中指定属性和json对象的关系,这里是statuses <- map["statuses"]

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

或者是另外一种:

基类里面像这样写:

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"parametersparametersencoding: .URLheadersnil)

                .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()

                    }

            })

    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

参考链接:http://www.cnblogs.com/sunshine-anycall/p/5170372.html

时间: 2024-08-01 02:23:02

Swift: Alamofire -> http请求 & ObjectMapper -> 解析JSON的相关文章

Swift: 用Alamofire做http请求,用ObjectMapper解析JSON

演示样例代码看最后. 跟不上时代的人突然间走在了时代的前列,果然有别样的风景.首先歧视一下AFNetworking.这个东西实在太难用了.不想封装都不行,要不写一大堆代码. NSURL *URL = [NSURL URLWithString:@"http://example.com/resources/123.json"]; AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:URL.

Android 网络请求json数据,解析json数据,生成对应的java bean类一步到位,快速开发

Android 网络请求一般都涉及到图片和JSON数据,怎样快速的请求网络JSON数据,解析JSON数据,并且一步生成自己想要的Java bean实体类?这个涉及到Android 开发效率的问题.由于接触Android 网络这方面比较多,自然就找到一些好的方法来快速开发Android 网络模块的相关内容,接下来就为大家揭晓 一步快速请求,解析JSON 数据生成对应的Java bean实体类的方法. 注:我们先把思路讲解下吧: 1.网络请求JSON数据代码可以自己写,当然我还是推荐使用网络上开源的

body-parser Node.js(Express) HTTP请求体解析中间件

body-parser Node.js(Express) HTTP请求体解析中间件 2016年06月08日     781     声明 在HTTP请求中,POST.PUT和PATCH三种请求方法中包含请求体,Node.js 原生HTTP模块中,请求体要基于流的方式接收和解析.body-parser是一个HTTP请求体解析中间件,使用这个模块可以解析JSON.Raw.文本.URL-encoded格式的请求体,Express框架中就是使用这个模块做为请求体解析中间件. 请求体解析 1.1 原生环境

0919-网络 请求 数据解析(掌握get post请求 解析json等代码即可)

http://localhost:8080/MJServer/video 复习看的: NSURLConnection 发送请求   暂时没有用到AFN 基本http请求 GET: - (IBAction)login { // 1.用户名 NSString *usernameText = self.username.text; if (usernameText.length == 0) { [MBProgressHUD showError:@"请输入用户名"]; return; } //

网络请求(listview json解析 数据库存储)【周五01.08】

adapter 包 MyBaseAdapter类 1 package com.cp.adapter; 2 3 import java.util.List; 4 5 import android.content.Context; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.BaseAdapter;

Java从网络中请求获取JSon数据以及解析JSON数据----(自创,请注明)

Json数据是比较常用的数据类型解析,优点就不多说啦.来看看方法: public static JSONObject getJsonObject(String url) { JSONObject jsonObject = null; try { HttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); HttpParams httpParams = httpClient.getPara

iOS开发之Alamofire源码深度解析

一.Alamofire核心模块概述 我们先整体上来看一下AlamoFire这个框架关系,概述一些核心模块.该部分我们先来看一下AlamoFire的文件组织结构,然后在给出这些文件组织结构中类的关系.所以在本部分类图是少不了的.废话少说,进入该部分的主题. 1.Alamofire的目录结构解析 首先我们来看一下AlamoFire的目录结构,从整体上来把控一下AlamoFire.下方截图是AlamoFire框架的所有文件,文件不算多,Alamofire框架的源代码并不算多,所有理清Alamofire

18 Ajax、Json以及jackson框架解析json的基本应用

1. Ajax (1)概念:ASynchronous JavaScript And XML 异步的JavaScript 和 XML 异步和同步:客户端和服务器端相互通信的基础上 * 客户端必须等待服务器端的响应.在等待的期间客户端不能做其他操作. * 客户端不需要等待服务器端的响应.在服务器处理请求的过程中,客户端可以进行其他的操作. Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. [1] 通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意味着可

利用fastjson解析json并通过js&amp;ajax实现页面的无跳转刷新

1.json是一种优秀的数据格式,在移动开发和web开发中经常用到,本例中通过一个小案例讲解如何通过alibaba的开源框架fastjson来解析jason数据格式并通过js实现无跳转刷新 2,新建一个web项目,这是我的项目:我这里直接用servlet写的 注意导包,我这里到了很多无用的包,其实主要的包是下面几个: 这个三个包是必须的,其他都是开发基本web的常用包 3.创建一个domain: package com.keson.domain; import com.thoughtworks.