Moya和高阶函数

  • 1.Moya
    • 1.1 Moya简介
    • 1.2 Moya 是如何一步步构建出来的?
  • 2. 高阶函数
    • 2.1 Map
    • 2.2 flatMap
    • 2.3 compactMap
    • 2.4 filter
    • 2.5 reduce
  • 2.6 高阶函数链式调用

1.Moya

1.1 Moya简介

我们日常都会和网络打交道不管是使用 AFN 还是 Alamofire ,虽然这两者都封装了 URLSession ,不用让我们使用官方繁琐的 API。久而久之我们会发现我们的APP中到处都散落着和 AFN 、 Alamofire 相关的代码,不便于统 一的管理,而且很多代码内容是重复的,于是我们就会新建一个中间层 Network layer 来统一 管理我们代码中 AFN 、 Alamofire 的使用。

于此同时我们仅仅希望我们的App只和我们的 Network layer 打交道,不用关系底层使用的那个 三方的网络库,即使进行迁移,也应该对我们的上层业务逻辑毫无变化,因为我们都是通过Network layer 来耦合业务逻辑的。

但是因为抽象的颗粒度不够,我们往往写着写着就会出现越过 Network layer , 直接和我们的三 方网络库打交道,这样就违背了我们设计的原则,而 Moya 就是对网络业务逻辑的抽象,我们 只需要遵循相关协议,就可以发起网络请求,而不用关系底层细节

1.2 Moya 是如何一步步构建出来的?

Moya 的模块可以大致分成这几类:

其次 Moya 主要的数据处理流程可以用下面这张图来表示Moya流程图,对于这张图我们一 点点来分析,我们先来看第一个阶段链接:

第一步创建了一个遵守 TargetType 协议的枚举,这个过程中我们完成网络请求的基本配置;

接下来通过 endpointClosure 的加工生成了一个 endPoint ,点击进入EndPoint的文件中,可以看到这里是对 TargetType 的一层再包装,其中endpointClosure的代码如下

public typealias EndpointClosure = (Target) -> Endpoint
public let endpointClosure: EndpointClosure
@escaping EndpointClosure = MoyaProvider.defaultEndpointMapping
final class func defaultEndpointMapping(for target: Target) -> Endpoint {Endpoint(url: URL(target: target).absoluteString,sampleResponseClosure: { .networkResponse(200, target.sampleData) }method: target.method,task: target.task,httpHeaderFields: target.headers)
}
EndpointClosure = {(Target)->Endpoint inEndpoint(url: URL(target: target).absoluteString,sampleResponseClosure: { .networkResponse(200, target.sampleDatmethod: target.method,task: target.task,httpHeaderFields: target.headers)}

以上就是关于 TargetType 通过 endpointClosure 转化为 endPoint 的过程。下一步就是利用 requestClosure ,传入 endPoint ,然后生成 request 。request 生成过程和 endPoint 很相似。整体上使用 do-catch 语句来初始化一个 urlRequest,根据不同结果向闭包传入不同的参数。一开始使用 try 来调用 endpoint.urlRequest() ,如果抛出错误,会切换到 catch 语句中去。至于 endpoint.urlRequest() 它其实做的事情很简单,就是根据前面说到的 endpoint 的那些属性来初始化一个 NSURLRequest 的对象。

   /// Closure that decides if and what request should be performed.public typealias RequestResultClosure = (Result<URLRequest, MoyaError>) -> Void/// Closure that resolves an `Endpoint` into a `RequestResult`.public typealias RequestClosure = (Endpoint, @escaping RequestResultClosure) -> Void/// A closure deciding if and what request should be performed.public let requestClosure: RequestClosure@escaping RequestClosure = MoyaProvider.defaultRequestMapping,final class func defaultRequestMapping(for endpoint: Endpoint, closure: RequestResultClosure) {do {let urlRequest = try endpoint.urlRequest()closure(.success(urlRequest))} catch MoyaError.requestMapping(let url) {closure(.failure(MoyaError.requestMapping(url)))} catch MoyaError.parameterEncoding(let error) {closure(.failure(MoyaError.parameterEncoding(error)))} catch {closure(.failure(MoyaError.underlying(error, nil)))}}

生成了 Request 之后,就交给 Provider 来发起网络请求了

    @discardableResultopen func request(_ target: Target,callbackQueue: DispatchQueue? = .none,progress: ProgressBlock? = .none,completion: @escaping Completion) -> Cancellable {let callbackQueue = callbackQueue ?? self.callbackQueuereturn requestNormal(target, callbackQueue: callbackQueue, progress: progress, completion: completion)}

看到上面发起请求调用了 requestNormal 方法。

 func requestNormal(_ target: Target, callbackQueue: DispatchQueue?, progress: Moya.ProgressBlock?, completion: @escaping Moya.Completion) -> Cancellable {let endpoint = self.endpoint(target)let stubBehavior = self.stubClosure(target)let cancellableToken = CancellableWrapper()// Allow plugins to modify responselet pluginsWithCompletion: Moya.Completion = { result inlet processedResult = self.plugins.reduce(result) { $1.process($0, target: target) }completion(processedResult)}if trackInflights {var inflightCompletionBlocks = self.inflightRequests[endpoint]inflightCompletionBlocks?.append(pluginsWithCompletion)self.internalInflightRequests[endpoint] = inflightCompletionBlocksif inflightCompletionBlocks != nil {return cancellableToken} else {self.internalInflightRequests[endpoint] = [pluginsWithCompletion]}}let performNetworking = { (requestResult: Result<URLRequest, MoyaError>) inif cancellableToken.isCancelled {self.cancelCompletion(pluginsWithCompletion, target: target)return}var request: URLRequest!switch requestResult {case .success(let urlRequest):request = urlRequestcase .failure(let error):pluginsWithCompletion(.failure(error))return}let networkCompletion: Moya.Completion = { result inif self.trackInflights {self.inflightRequests[endpoint]?.forEach { $0(result) }self.internalInflightRequests.removeValue(forKey: endpoint)} else {pluginsWithCompletion(result)}}cancellableToken.innerCancellable = self.performRequest(target, request: request, callbackQueue: callbackQueue, progress: progress, completion: networkCompletion, endpoint: endpoint, stubBehavior: stubBehavior)}requestClosure(endpoint, performNetworking)return cancellableToken}

endPoint 这个我们再上面的代码分析中已经说过了,stub 是有关测试桩的代码这里我们都暂且忽略,cancellableToken 是取消的标识,如果有取消的标识,那么isCancelled就会为true。

internal class CancellableWrapper: Cancellable {internal var innerCancellable: Cancellable = SimpleCancellable()var isCancelled: Bool { innerCancellable.isCancelled }internal func cancel() {innerCancellable.cancel()}
}internal class SimpleCancellable: Cancellable {var isCancelled = falsefunc cancel() {isCancelled = true}
}

CancellableWrapper 是对 SimpleCancellable 的又一层包装,都遵循了 Cancellable 的协议, 这里我们也可以遵循自己定义的协议,所以这里我们可以看到当前的 Class 都是 internal。接下来就是 performNetworking 这个闭包表达式的分析,我们先一步步来看

如果取消请求,则调用取消完成的回调, 直接 return,不再执行闭包内下面的语句。否则就调用
requestClosure(endpoint, performNetworking)
requestClosure的默认实现是MoyaProvider.defaultRequestMapping。

那么如果请求成功,就会调用closure

2. 高阶函数

高阶函数的本质也是函数,有两个特点

  • 接受函数或者是闭包作为参数
  • 返回值是一个函数或者是闭包

2.1 Map

对数组进行循环,并对数组中的每个元素采取相同的操作,然后返回数组。
看到map接受闭包作为参数,并且返回值是范型集合。

这里可以使用map将字符串全都变成大写

简写:

2.2 flatMap

flatMap接受闭包作为参数,返回当前元素的集合。

flatMap 中的闭包的参数同样是 Sequence 中的元素类型,但其返回类型为
SegmentOfResult。在函数体的范型定义中, SegmentOfResult 的类型其实就是 Sequence
而 flatMap 函数返回的类型是: SegmentOfResult.Element 的数组。从函数的返回值来看,与
map 的区别在于 flatMap 会将 Sequence 中的元素进行 “压平”,返回的类型会是
Sequence 中元素类型的数组,而 map 返回的这是闭包返回类型的数组。

相比较我们的 map 来说,flatMap 最主要的两个作用一个是压平数组,一个是过滤数组空值。

2.3 compactMap

当转换闭包返回可选值并且你期望得到的结果为非可选值的序列 时,使用 compactMap 。

其实flatMap也能做到同样的效果,但是系统推荐使用compactMap。

2.4 filter

遍历数组,过滤不满足条件的元素后返回满足条件的元素组成的数组,也就是允许调用者传入一个闭包来过滤集合中的元素。

2.5 reduce

reduce 把集合中所有的值结合起来返回一个新的值。

查看reduce的源代码,首先这里传入一个初始值,然后传入一个闭包表达式,返回值和初始值的类型一样为泛型Result。这里将初始值赋值给accumulator,然后遍历数组中的element执行nextPartialResult。

那么如果我们想要找到数组中的最大值,我们也可以使用reduce。

那么如果想要逆转一个数组,也可以使用reduce

2.6 高阶函数链式调用

计算数组中偶数的平方和

也可以只使用reduce来完成。

Swift —— Moya和高阶函数相关推荐

  1. Swift 中的高阶函数

    一.概念 高阶函数是将一个或多个函数作为参数或返回一个函数作为其结果的函数 二.Swift的集合类型中的高阶函数 1.Map 对于原始集合里的每一个元素,以一个变换后的元素替换之形成一个新的集合 le ...

  2. Swift 烧脑体操(三) - 高阶函数

    前言 \\ Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说 ...

  3. Swift 基础 高阶函数 forEach filter map compactMap compactMapValues flatMap reduce sort sorted shuffled ...

    一直觉得自己写的不是技术,而是情怀,一个个的教程是自己这一路走来的痕迹.靠专业技能的成功是最具可复制性的,希望我的这条路能让你们少走弯路,希望我能帮你们抹去知识的蒙尘,希望我能帮你们理清知识的脉络,希 ...

  4. Swift的高阶函数

    Swift的高阶函数 swift常用高阶函数 1. map 2. flatMap 3. filter 4. reduce swift常用高阶函数 swift中比较常用的高阶函数有:map.flatMa ...

  5. Swift 常用高阶函数

    Swift 常用高阶函数 map函数 对每一个元素进行运算 计算每一个元素的count 对元素进行大小写变换 转换类型 sorted函数 从小到大排序 从大到小排序 flatMap函数 降维 过滤元素 ...

  6. Go 学习笔记(61)— Go 高阶函数、函数作为一等公民(函数作为输入参数、返回值、变量)的写法

    函数在 Go 语言中属于"一等公民(First-Class Citizen)"拥有"一等公民"待遇的语法元素可以如下使用 可以存储在变量中: 可以作为参数传递给 ...

  7. 2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法

    目录 高阶函数用法 作为值的函数 匿名函数 柯里化(多参数列表) 闭包 高阶函数用法 Scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是"头等公民",它和Int. ...

  8. Koltin 高阶函数

    高阶函数 高阶函数是将函数用作参数或返回值的函数. 在java中函数和方法是同一个概念, 我就把高阶函数理解为:高阶函数是将方法用作参数或返回值的方法, java中我们要调用方法里面的参数一般需要实现 ...

  9. 函数 tostring_Kotlin实战之Fuel的高阶函数

    Fuel 是一个用 Kotlin 写的网络库,与 OkHttp 相比较,它的代码结构比较简单,但是它的巧妙之处在于充分利用了 Kotlin 的语言特性,所以代码看上去干净利落. OkHttp 使用了一 ...

  10. 【廖雪峰Python学习笔记】高阶函数

    Higher-order function 高阶函数 映射 过滤算法 排序算法 高阶函数 变量可指向函数 >>> abs # 函数 <built-in function abs ...

最新文章

  1. stm32驱动ssd1306配置_STM32 OLED 屏幕 驱动芯片SSD1306 IIC代码
  2. js中的Object.create(null) 和 {} 的区别
  3. PyQt5学习--基本窗口控件--加载文件-QFileDialog
  4. IDF2013:可信计算在中国的发展
  5. 连续整数--全国模拟(一)
  6. 西南科技大学OJ系统 #941: 有序顺序表的合并操作的实现
  7. 物联网嵌入式学习路线
  8. File Based Optimizations(FBO,FBO焕新存储技术)介绍
  9. Unity 日志输出
  10. [渝粤教育] 西安建筑科技大学 技术经济学 参考 资料
  11. 连环锁 POJ - 1832(格雷码与二进制)
  12. 计算机网络知识点————交换机
  13. jvm 年轻代、年老代、永久代
  14. python爬虫网易云音乐最热评论并分析_网易云音乐热门评论api分析
  15. windows自带Bitlocker使用问题汇总
  16. 基于51单片机的洗衣机控制系统
  17. go敏感词过滤工具wordsfilter
  18. C++的动态多态,Virtual关键字的作用
  19. 如何用公式编辑器打除号?
  20. 访问学者在加拿大游玩,有哪些名胜古迹?

热门文章

  1. PS利用切片工具将一张大图裁剪成多个子图像并导出
  2. 1-2 实验2 点对点通信
  3. h5底部输入框被键盘遮挡_搜遍整个谷歌, 只有我是在认真解决安卓端hybrid app键盘遮挡输入框的问题...
  4. win7浏览器主页修改不过来_ie主页被锁定无法修改怎么办?ghost win7 ie主页修改不了的两种解决方法...
  5. 碳足迹审核的计算有几种方法?
  6. 不同类型的变量存放对应类型的数据,变量的值可以改变
  7. okvis 基于关键帧视觉惯性传感器非线性优化SLAM 论文翻译+博客总结
  8. 2021西湖论剑hardrsa
  9. Linux网页版操作
  10. spark写出分布式的训练算法_Spark on Angel