说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

在Swift中,如何更优雅地处理网络返回数据?

HTML文档下载 WORD文档下载 PDF文档下载
在iOS开发中进行网络请求时,一般是获取到服务器返回的data后,再根据需求转换成JSON,图像等信息。在Swift时代,如何使用泛型和extension来让数据解析工作更加优雅?且看本文详解。

一、过去这么干

我们在iOS开发中进行网络请求的时候,一般是获取到服务器返回的data后,再根据我们的需要转换成JSON,图像等信息:

 let myURL = NSURL(string: "http://imgs.xkcd.com/comics/scrabble.png")!        let task = NSURLSession.sharedSession().dataTaskWithURL(myURL, completionHandler: { (data, response, error) -> Void in            let image = UIImage(data: data)            //use the image        })

但如果你的应用中存在各种类型的返回数据,那么你可能就要在各个网络请求的中进行重复的处理了。

二、在Swift-beta时代

下面,我们使用swift中的泛型和extension让你的数据解析工作更优雅。

首先我们建立一个protocol:

public protocol ResponseConvertible{    class func convertFromData(data:NSData!) -> (Self?,NSError?)}

这个protocol负责把网络请求返回的NSData转化成我们想要的任何类型。 相信大家应该注意到了返回中的Self了,把返回定义为Self是因为这个接口本身是没有包含类型信息的,我们并不知道哪个类会实现这个接口,所以我们使用Self来指代将要实现这个接口的类。 接着,我们使用extension来为JSON(我使用的是SwiftJSON),UIImage,NSData这三个类实现我们的ResponseConvertible接口:

extension JSON:ResponseConvertible{    public static func convertFromData(data:NSData!) -> (JSON?, NSError?){        let value = JSON(data: data, options: NSJSONReadingOptions.MutableContainers, error: nil)        switch value.type{        case .Null:            return (value, value.error)        default:            return (value, nil)        }    }}extension NSData:ResponseConvertible{    public class func convertFromData(data: NSData!) -> (NSData?, NSError?) {        return (data,nil)    }}extension UIImage:ResponseConvertible{    public typealias Result = UIImage    public class func convertFromData(data: NSData!) -> (UIImage?, NSError?) {        return (UIImage(data: data),nil)    }}

然后,我们再新建一个名为MyRequest的自定义的网络请求类:

class MyRequest <  T:ResponseConvertible> {      var url:NSURL      init(url:NSURL) {          self.url = url      }      //这里用一个简单的请求进行说明,实际应用中可以构建一个最适合你的网络请求框架      func aSimpleRequest(completionHandler:(T?,NSError!) -> ()){          let session = NSURLSession.sharedSession()          let task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in              if error == nil{                  //用ResponseConvertible接口进行数据转换                  let(object, converError) = T.convertFromData(data)                  completionHandler(object,converError)              }          })          task.resume()      }  }  

好了,准备工作完成,我们终于可以使用优化后的请求方法了。请求时,< T:ResponseConvertible>接受一个实现了ResponseConvertible接口的类型,例如UIImage:

let myURL = NSURL(string: "http://imgs.xkcd.com/comics/scrabble.png")!        MyRequest<  UIImage>(url: myURL).aSimpleRequest({image,error in            self.imageView.image = image        })

这样,我们只要在发起请求前定义好我们需要返回的类型,接口就会如愿地为你返回该类型的数据了。是不是比文章一开始的方法优雅多了?

三、现在应该这么干

不过,如果你现在把以上代码拷贝进你运行在Xcode6正式版的项目,你会发现Xcode会报错:


错误详情:

Protocol 'ResponseConvertible' requirement 'convertFromData' cannot be satisfied by a non-final class ('NSData') because it uses 'Self' in a non-parameter, non-result type position

而这些代码在Swift-beta时代是能正常运行的。看来苹果在Swift1.0中对Self的用法进行了修改。

根据错误的提示,我们需要把使用了Self的类定义为final,而这在自定义的类中的确有用:

final class MyClass: {    //...}

但是对于UIImage,NSData这些系统的类就无能为力了。这个问题困扰了我好一会,stackoverflow无果,请教一些盆友都表示对Self的用法不熟或压根没动过Swift。

最后,还是在typealias的帮助下绕过了,typealias 可以为已经存在的类型和方法重新定义一个快捷名字,比如:

typealias Result = UIImage

这里的Result就相当于UIImage类型了。 引入typealias后,以上的代码做如下修改,就能在新版本的Xcode下运行了:

public protocol ResponseConvertible{    typealias Result    class func convertFromData(data:NSData!) -> (Result?,NSError?)}
extension JSON:ResponseConvertible{    public typealias Result = JSON    public static func convertFromData(data:NSData!) -> (Result?, NSError?){        let value = JSON(data: data, options: NSJSONReadingOptions.MutableContainers, error: nil)        switch value.type{        case .Null:            return (value, value.error)        default:            return (value, nil)        }    }}extension NSData:ResponseConvertible{    public typealias Result = NSData    public class func convertFromData(data: NSData!) -> (NSData?, NSError?) {        return (data,nil)    }}extension UIImage:ResponseConvertible{    public typealias Result = UIImage    public class func convertFromData(data: NSData!) -> (UIImage?, NSError?) {        return (UIImage(data: data),nil)    }}
class MyRequest< T:ResponseConvertible> {    //这里用一个简单的请求说明,实际应用中可以构建一个最适合你的网络请求框架    var url:NSURL    init(url:NSURL) {        self.url = url    }    func aSimpleRequest(completionHandler:(T.Result?,NSError!) -> ()){        let session = NSURLSession.sharedSession()        let task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in            if error == nil{                let(object, converError) = T.convertFromData(data)                completionHandler(object,converError)            }        })        task.resume()    }}

使用:

let myURL = NSURL(string: "http://imgs.xkcd.com/comics/scrabble.png")!        MyRequest<  UIImage>(url: myURL).aSimpleRequest({image,error in            self.imageView.image = image        })

本文转载自:简书

(责编/唐小引)

Visual Studio 2013 Preview新功能预览 “中国手机游戏四月流水榜”出炉 超半数基于Cocos2d-x引擎 为移动而设计之信息架构篇 难逃厄运:Zynga将关闭Draw Something母公司OMGPOP 直接拿来用!最火的iOS开源项目(一) 是时候抛弃Eclipse转向IntelliJ了 Arrow:轻量级的Python时间日期库 编程语言API,你最青睐哪一款? 推动新输入方式发展:英特尔为感知计算设1亿美元基金 AWS到底有多大?目前看来有158000台服务器 C语言实现树的动态查找 第五届中国云计算大会于北京隆重举行 改变企业移动化:新Google地图API支持用户定制 诺基亚旗舰手机EOS真机图曝光 配备“巨型”摄像头 走进豆瓣:豆瓣的技术架构与团队文化分享 加速Web开发的10款HTML5工具 微软式微?AMD、英特尔等开始疏远Windows 语音技术现状:四千万突破语音产业的技术壁垒? 万维网联盟W3C推荐Web性能API 微软郑子颖:Windows Azure如何支持开源系统和软件? EMC 叶成辉:软件定义数据中心实现统一、开放的管理 百度云主任架构师 侯震宇:云终端开启数字生活 中国工程院院士 倪光南:中国云计算在全世界份额远超3% 信息图:未来的企业移动培训应用与技术 “2013年度中国优秀开源项目征集”活动最后三天 为什么开发者倾向于使用杂乱无章的免费工具 EMC合作伙伴销售经理杜术清:实现云的三种途径 开发者想走向海外:你融入老外的圈子了吗? 前微软工程师:美国监控和直接访问服务器?这不太可能 代码、TDD速查表 如何选择前端架构:服务器端HTML vs. JS部件 vs.单页Web应用 急,在线等待!!! 如何调用保存对话框? Together for VS.NET 两个网关的问题!在线等,结贴快! 数据库中表的问题(100分) "#program once"是什么意思? 关于JTable的问题 局部钩子能影响其它软件???? SQL Server数据库中字段取中文名好,还是取英文名好? 怎么查询一个表,当用户新增一个记录时 如何防止listCtrl的列被拖动? 我的sony记忆棒,在相机可以读,可是不能在电脑读取,请帮忙! 安装.net的菜鸟问题,帮忙```````急```` 请Skt32(荒城之月)和gzshd(郁闷)大侠进来拿分! 有汉字输入的字符串,要限定其长度不超过100个字符,用正则表达式如何实现? 0x69514818指令引用的“0x14084268”内存错误 大家觉得以下哪一种 C语言 开发工具比较好?谢谢。 有关利用ms中的函数scardconnect()读手机sim卡的问题(很急!!) 从word 表格里面导入文本到Access 文件中没了回车换行,怎么解决? 如何将非主窗体放到任务栏里!!(在线等待) 打印RichTextBox中的文本 小弟长角了,散分! 装了sp4结果系统老是重启 急, 插入数据的时候怎么解决主键的问题?? 用C#做一個項目,應怎樣去規划? 一个简单问题!!! 上海的威迅,有人听说过吗??如何??? 2000提示:在系统启动时至少有一个程序或驱动程序发生错误,怎么解决 针对接口编程,而不是针对实现编程 请教:自定义查询 各位兄弟,帮帮手呀. 一时想不明白,请教一下。。。 500分求解答!关于数据库的发布!在线等候!!!! 我不会制作mschart.ocx文件,看过一些文章,介绍的太笼统,谁能有详细的制作步骤,或者告诉我哪里有mschart.cab文件下载最好了,谢谢 高分紧急求救(教)! 已知文件名,如何知道它是被哪个程序/进程打开的,并关闭相应的程序或进程? 简单:函数的参数列表问题(c) 在CDialogBar类的对象上按放一个按钮控件,运行时为什么该按钮控件是灰色的? 为中国头你神圣的一票 我在当前项目里要继承另一个项目里的一个类,在VS.NET里要调些什么才能实现。 关于c#中的数据库开发。 word打字时按空格键时留下小点 又是一年月圆夜,月下为你许三愿:一愿美梦好似月儿圆,二愿日子更比月饼甜,三愿美貌犹如月中仙。:) 我的IE字体不知怎么变大了,老也改不回来。 backup database shell error? 域的问题 大四的苦恼 一个小问题! 请教关于SESSION的问题! 准备贩卖人参去了?? 似乎感觉C++ Primer程序结构有点乱.... 求七年级下册100道单项选择题~~附答案 七年级下册.求英语选择题及回答.要有点难度的. 耳中人(蒲松龄)为什么“谭晋玄”耳中曾经有“小人”的原因 蒲松龄的《耳中人》产生的原因是什么? 蒲松龄的《狼》全文3段都有 原文和译文 注释 小学六年级上册第四单元作文476个字,今晚写作文那. 求关于x的方程lx-2l+lx+5l=8的解 已知2x-4-1,化简lx-2l+lx+5l已知2x-4-1,化简Ⅰx-2Ⅰ+Ⅰx+5Ⅰ(“Ⅰ”表示绝对值) decision taking 与decision making有什麼区别? 物理电学中U=U1+U2这里U1和U2分别代表什么?串联电路电压的特点:串联电路的总电压等于各部分电压之和。U=U1+U2 卖衣服要用什么法则?三个英文字母的 莫斯科市民发起“落叶保卫战”荷兰发现139幅二战被纳粹掠夺珍贵油巴西前首富申请破产保护 身家蒸发99希腊前外长称希情报报门曾监视美国大使香港警方破获今年最大宗非法外围赌博案监察部发布《监察机关特邀监察员工作办规避新规企业花样百出 同工同酬成“纸中注协发布6项审计准则问题解答 明年直拍悉尼社区万圣节前夕:化妆成小鬼儿斯诺登新照:在莫斯科乘游览船 未戴眼秘鲁组成新内阁长春举行消防知识竞赛一等奖获得奖金98日来听竹笛吧城市信报图文版3年建设项目新开工969个城市信报图文版做好培养选拔干部工作 提高组织工作科户户争抢改厕“指标” 在山海关区后七双北市瓦斯公司嗅剂外泄 居民睡梦中被\"问题巨星\"孙杨:师徒决裂险毁前娱乐圈上演超生游击队 明星私生子变最楼市“金九银十”收官 北上广深房价涨双生鬼瞳一品功夫王法师王座知识就是力量东方武者疯狂基地满清妖孽通神录菲儿剑圣纵横之玩转逍翷妖都传建阳旅游白玉旅游屯昌旅游闽清旅游龙兴旅游广丰旅游富平旅游青阳旅游依兰旅游龙州旅游石渠旅游
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘