ReactiveCocoa中lift的使用方法
我对这个方法的理解是:转化现有的信号为我们需要的新的信号,并且在信号发出start()信号时才启动
先来看个简单的栗子吧:
/**
由给定的信号操作符创建一个新的信号
*/
func liftExample() {
let transform: Signal -> Signal = {
signal in
return signal.map { "I have get \($0)" }
}
SignalProducer(value: 100)
//.lift(transform)
.startWithNext { print($0) }
}
这里如果我们不加lift的话打印出来的是100,但是把lift加上的话,打印出来的是I have get 100
来看看lift方法中调用的transform里到底什么意思:把原有的
return signal.map { "I have get ($0)" }的意思是原有的信号经过map转变成string字符串类型,并发送.
下面在写个例子--我把它步骤分解下。看其怎么一步一步实现的
//创建转换的类型--- Signal<[Int], NoError> -> Signal<[Int], NoError>
let transform: Signal<[Int], NoError> -> Signal<[Int], NoError> = {
//原来的信号
originalSignal in
//创建新的信号
let (resultSignal, resultObserver) = Signal<[Int], NoError>.pipe()
//原来的信号发送信号
originalSignal.observeNext({ originalArr in
//把原有信号中的数组中每个元素做乘 5 再加 2 的操作,并返回一个接受此结果的新数组
let newArr = originalArr.map { $0 * 5 + 2 }
//新信号的观察者发送信号-----最重要一定要新信号的观察者发送信号,外界才能做出反应
resultObserver.sendNext(newArr)
})
// 返回新的信号
return resultSignal
}SignalProducer<[Int], NoError>(value: [1, 2, 3, 4, 5])
.lift(transform)
.startWithNext { result in
print(result)
}
打印出的结果为 [7, 12, 17, 22, 27]
下面再举个我项目中有点麻烦的一个例子---
项目中需要获取城市列表,但是后台给的是两段式获取的。。即先获取获取全部的省,然后在根据省ID来获取下面的市。但是我想要是的一个数组类型---[“省名称”: [市]]。下面直接放代码
typealias CityDic = [String: [City]]
let cityDic = MutableProperty(CityDic())/**
获取城市列表
*/
mutating private func getCityList() {
let transform: Signal<[City], NetRequestError> -> Signal = {
citysSignal in
let (resultSignal, resultObserver) = Signal.pipe()
citysSignal.observe({ event in
switch event {
case let .Next(provinces):
//这里获取到的是全部的省--需要再进一步获取到全部的市//在这里一定要创建GCDgroup,因为网络请求是异步的,如果不加入group的话,它会先直接返回结果,然后在请求网络
let group = dispatch_group_create()
var dict = CityDic()
provinces.forEach({ (province) in
//这里一定要在循环里面dispatch_group_enter,不能放在外面---因为一个循环就是一个网络请求
dispatch_group_enter(group)
NetHelper.sharedInstance.requestProvider
.request(RequestAPI.getCityList(type: CityType.city, parentId: province.id))
.mapResponseToObjArray(City)
.start({ event in
switch event {
case let .Next(value):
dict.updateValue(value, forKey: province.name!)
dispatch_group_leave(group)
caselet .Failed(error):
//这里,无论是失败还是成功,或者是其他什么。请立即退出group----dispatch_group_leave(group)
resultObserver.sendFailed(error)
dispatch_group_leave(group)
default:
dispatch_group_leave(group)
return
}
})
})
dispatch_group_notify(group, dispatch_get_main_queue(), {
//然后,在GCD group收到结束通知的时候,在主线程里观察者发送结果
resultObserver.sendNext(dict)
})
default:
break
}
})
return resultSignal
}
NetHelper.sharedInstance.requestProvider
.request(RequestAPI.getCityList(type: CityType.province, parentId: nil))
.mapResponseToObjArray(City)
.lift(transform)
.startWithResult { result in
switch result {
case let .Success(value):
self.cityDic.value = https://www.it610.com/article/value
case let .Failure(error):
print(error)
}
}
}
【ReactiveCocoa中lift的使用方法】注:这里面用到了我之前写道的 一篇文章里的内容, 使用Moya+ReactiveCocoa 进行网络请求,那篇文章里面也用到了lift,大家有兴趣的话,可以去看看http://www.jianshu.com/p/7bf635577900
这里面最主要的是要用GCD group~~而且是dispatch_group_enter(group) 以及dispatch_group_leave(group),不能用dispatch_group_async(dispatchGroup, dispatchQueue, ^(){ NSLog(@"dispatch-1"); }); ,因为,网络请求是一个操作,但是网络请求返回结果又是一个操作----切记切记
推荐阅读
- 投稿|产品“白送”+溢价入股,赛诺菲打响抄底中国生物科技资产第一枪
- 我的中国节
- 二叉树前中后序遍历的实现(递归和非递归版)
- 春日还未于冬日的遥遥无期中惊醒
- Android中的线程相关
- 程序员|Java线程池中的线程复用是如何实现的(稳进大厂)
- 喝醉了怎么解酒?喝酒前中后吃什么解酒?
- ReactiveCocoa|ReactiveCocoa 学习笔记(三)
- 中年女上司在职场上会无故为难年轻漂亮女孩吗()
- 听说他开了一个我们梦想中的院子