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
    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还有很多其他的功能。如果需要了解更多可以查看官方文档

或者是另外一种  方法二:

  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"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

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

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

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

  2. iapp,iapp http请求,iapp解析json数据

    iapp发送http请求,并解析json数据 //http操作 t() { s a = "http://wap.baidu.com/" //目标url hs(a, null, nu ...

  3. autojs,autojs 发送http请求,autojs 解析json数据

    如题,我这个就直接上代码吧 (function () { let request = http.request; // 覆盖http关键函数request,其他http返回最终会调用这个函数 http ...

  4. [Swift]SwiftyJSON的使用:解析JSON

    用法 初始化Initialization import SwiftyJSON let json = JSON(data: dataFromNetworking) 或者 let json = JSON( ...

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

    body-parser Node.js(Express) HTTP请求体解析中间件 2016年06月08日     781     声明 在HTTP请求中,POST.PUT和PATCH三种请求方法中包 ...

  6. 在线聊天项目1.4版 使用Gson方法解析Json字符串以便重构request和response的各种请求和响应 解决聊天不畅问题 Gson包下载地址

    在线聊天项目结构图: 多用户登陆效果图: 多用户聊天效果图: 数据库效果图: 重新构建了Server类,使用了Gson方法,通过解析Json字符串,增加Info类,简化判断过程. Server类代码如 ...

  7. 阶段一:通过网络请求,获得并解析JSON数据(天气应用)

    “阶段一”是指我第一次系统地学习Android开发.这主要是对我的学习过程作个记录. 在上一篇阶段一:解析JSON中提到,最近在写一个很简单的天气预报应用.即使功能很简单,但我还是想把它做成一个相对完 ...

  8. 使用jQuery解析JSON数据(由ajax发送请求到php文件处理数据返回json数据,然后解析json写入html中呈现)

    在上一篇的Struts2之ajax初析中,我们得到了comments对象的JSON数据,在本篇中,我们将使用jQuery进行数据解析. 我们先以解析上例中的comments对象的JSON数据为例,然后 ...

  9. 异步POST请求解析JSON

    异步POST请求解析JSON 一.创建URL NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/order ...

随机推荐

  1. 线索thread二叉树

    对于一个普通的二叉树 我们可以很明显的看到,在一个二叉树中,会有许多的空结点,而这些空结点必然会造成空间的浪费,为了解决这个问题,我们可以引入线索二叉树,把这些空结点利用起来,利用 '^' 记录给定结 ...

  2. Python 跳出多重循环

    Python 本身没有“break n” 和“goto” 的语法,这也造成了Python 难以跳出多层(特定层数)循环.下面是几个跳出多层(特定层数)循环的tip. 1.自定义异常   class g ...

  3. mysql的存储引擎如何选择

    myisam:如果表对事务要求不高,用时以查询和添加为主,我们考虑myisam存储,如bbs中的发帖表.回复表 innodb:对事务要求高,保存的数据都是重要的数据,我们建议使用innodb,比如订单 ...

  4. IMAGE服务器软件配置

    NFS: vim /etc/exports /bak/www/www.xxxl.com/public/ 10.20.10.0/24(rw,sync,no_root_squash)/bak/www/ww ...

  5. awk中{print $1}什么意思

    给你举个例子,echo "aa bb cc" | awk -F '{print $1}' 结果就是aa,意思是把字符串按空格分割,取第一个,自己做个测试就明白了!awk是用来提取列 ...

  6. java 图形界面 Socket编程

    一.使用图形界面实现客户端服务器端的通信: 上代码: 服务器端代码: package cn.MyNET; import java.io.*; import java.net.*; import jav ...

  7. oracle行转列函数

  8. Chapter 1 First Sight——31

    I took notes carefully anyway, always looking down. 不论怎么样我都仔细的记着笔记,一直低着头. I couldn't stop myself fro ...

  9. DOM操作-倒排序子元素

    代码: —————————————————————————————— <script type="text/javascript">                // ...

  10. cmstop中实例化controller_admin_content类传递$this,其构造方法中接收到的是--名为cmstop的参数--包含cmstop中所有属性

    主程序cmstop类,实例化controller_admin_content类(接收请求后拼接的).传递cmstop所有属性过去.controller_admin_content.构造方法中接收到名称 ...