转载

在 Swift 中使用泛型和结构体来构建网络层

objc.io 推出一个新的谈话节目,一周一期,每期的主题固定,用 20 多分钟的时间去详述一个主题,很有意思,近期做个记录,内容比较简单就不翻译了,主要记录一下背后的思想。

一般网络层所做的工作无非就是发起请求,得到 NSData,然后进行 json 解析,接着映射成对应的 Model,最后传递给回调函数。比如我想得到一个填满 Episodes 类型的数组,但网络只能给你返回一个 id 类型,如果用传统的 OC 来写,这背后就涉及到复杂的类型转换,上面提到的每一步都可能出错。不过在 Swift 中我们有更好的办法。

1. 架构

创建了一个带泛型参数的 Resource<A> 结构体作为网络请求和 Model 交流的中间层:

在 Swift 中使用泛型和结构体来构建网络层

2. 各司其职

2.1 Webservice

Webservice 专门负责网络请求,它需要 Resource<A> 提供一些必要的网络请求的参数,并且将网络请求得到的数据(NSData)传递给 Resource<A> 的解析函数

final class Webservice {       func load<A>(resource: Resource<A>, completion:(A?)->()) {         NSURLSession.sharedSession().dataTaskWithURL(resource.url) { data, _, _ in             let result = data.flatMap(resource.parse)             completion(result)         }.resume()     } }

2.2 Resource

提供网络请求需要的一些参数和一个把 NSData 解析成 Model 的函数,我们使用泛型参数 A 来限定 Model 的类型。

struct Resource<A> {       let url: NSURL     let parse: NSData -> A? }

上面提到了 Resource<A> 结构体的两个主要功能:

  • 提供网络请求所需要的参数
  • 解析函数

我们可以直接在初始化里赋值:

extension Resource {       init(url: NSURL, parseJSON: AnyObject -> A?) {         self.url = url         // 直接赋值一个 block 解析的实现         self.parse = { data in             let json = try? NSJSONSerialization.JSONObjectWithData(data, options: [])             return json.flatMap(parseJSON)         }     } }

重点来关注一下解析函数:前面说过 Resource 的作用是将网络请求到的 data 解析成 Model,因为 Resource 并不关心 Model 的具体类型,所以这里分为两步走,Resource 负责把 NSData 解析成 AnyObject,而剩下的事情交给具体的 Model 去映射。为了解耦采用了回调的方式将 json(AnyObject)传递给相关 Model 处理。

2.3 Model 层

主要负责 Json 对象到 Model 的映射

typealias JSONDictionary = [String:AnyObject]  struct Episode {       let id :String     let title: String }  extension Episode {       init?(dictionary: JSONDictionary) {         guard let id = dictionary["id"] as? String,             let title = dictionary["title"] as? String else {return nil}         self.id = id         self.title = title     } }

上面说了 Resource 只负责从 NSData 解析到 AnyObject( NSData -> AnyObject ),剩下的 AnyObject -> A? 由 Model 层接管,我们可以初始化一个 Resource 类型常量,传入 AnyObject -> A? 的实现

extension Episode {       static let all = Resource<[Episode]>(url: url) { json in         if let dictionarys = json as? [JSONDictionary] {             return dictionarys.flatMap(Episode.init)         }         return nil     } }

4. 优势

  • 实现了高内聚低耦合,每个模块功能单一,彼此间采用函数的方式进行串联
  • 利用泛型在多处对 Model 类型做了限定,比如 Webserviceload<A>(resource: Resource<A>, completion:(A?)->())Resource let parse: NSData -> A? ,利用泛型约束编译器可以在编译期就发现错误,而不用等到运行时崩溃了才去查错。

5. One More Thing

谈话到此结束,让我们发散一下思维,其实还可以为 Resource 添加更多的网络请求参数,比如:

struct Resource<A> {       let path: String     let method : Method     let requestBody: NSData?     let headers : [String:String]     let parse: NSData -> A? }

添加独立的错误处理模块

public enum Reason {       case CouldNotParseJSON     case NoData     case NoSuccessStatusCode(statusCode: Int)     case Other(NSError?) }  struct Failure {       static func defaultFailureHandler(failureReason: Reason, data: NSData?) {         let string = NSString(data: data!, encoding: NSUTF8StringEncoding)         println("Failure: /(failureReason) /(string)")     } }

更新 Webservice

func load<A>(resource: Resource<A>, failure: (Reason, NSData?)->(), completion:(A?)->()) {       ...... }

-EOF-
在 Swift 中使用泛型和结构体来构建网络层
如果感觉此文对你有帮助,请随意打赏支持作者 :kissing_heart:

原文  https://chengway.in/zai-swift-zhong-shi-yong-fan-xing-he-jie-gou-ti-lai-gou-jian-wang-luo-ceng/
正文到此结束
Loading...