最新的ReactiveCocoa使用网上能找到的资料特别少,为了给接入swift版reactivecocoa的开发者提供便利,我就讲常用场景下的使用, 就拿注册页面来举例,如有异议和问题欢迎指正交流,言归正传,注册页面一般由一些信息需要用户填写,一般我们用UITableView展示,UITableView的使用我就不提了,上代码
fileprivate let verifyCode = MutableProperty<String>("")
....
func verifyCodeCell(at indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "verify_cell", for: indexPath) as! ABVerifyCodeCell
self.verifyButton = cell.verifyCodeButton
// import Then
return cell.with {
$0.textField.reactive.text <~ self.verifyCode.producer.take(until: cell.reactive.prepareForReuse)
$0.textField.reactive
.continuousTextValues
.take(until: cell.reactive.prepareForReuse)
.map { $0 ?? "" }
.observeValues{ [weak self] in
self?.verifyCode.value = String($0.characters.prefix(6))
}
$0.verifyCodeButton.reactive
.controlEvents(.touchUpInside)
.take(until: cell.reactive.prepareForReuse)
.observeValues { [weak self] _ in
self?.getVerifyCode()
}
}
}
由于cell重用问题,textField内容绑定必须调用以下方法来实现重用时解除之前的绑定
$0.textField.reactive.text <~ self.verifyCode.producer.take(until: cell.reactive.prepareForReuse)
以下代码用来限制输入的字符数,开发者也可以再次限制输入的内容,如手机号码校验等
.observeValues{ [weak self] in
self?.verifyCode.value = String($0.characters.prefix(6))
}
一切尽在代码中,文笔太差就不多废话了
在需要多个请求都返回时才处理后续流程这种情况下,如果不使用ReactiveCocoa,需要保留很多状态
使用ReactiveCocoa就简单多了,贴代码
func requestPropertyValue() -> SignalProducer<PropertyValueModel, RequestError> {
return SignalProducer { (observer, lifeTime) in
let params = ["module" : PropertyValueService.ModuleProperty.prod.rawValue]
let requestTask = PropertyValueService()
.request(
params,
transform: {
var result = [String : String]()
$0["data"].arrayValue.forEach {
result[$0["mappingName"].stringValue] = $0["propName"].stringValue
}
return PropertyValueModel(propMap: result)
},
completionHandler: {
if $0.isSuccess {
observer.send(value: $0.value!)
observer.sendCompleted()
} else {
observer.send(error: $0.error as! RequestError)
}
})
lifeTime += AnyDisposable {
requestTask?.cancel()
}
}
}
func requestProductCustomerNo() -> SignalProducer<String, NoError> {
return SignalProducer { observer, _ in
ProductNoService()
.request(
nil,
transform: { $0["prodCustomNo"].stringValue },
completionHandler: {
observer.send(value: $0.isSuccess ? $0.value! : "")
observer.sendCompleted()
})
}
}
func requestCustomerNoAndPropertyValue() {
let customerNoProducer = requestProductCustomerNo().promoteError(RequestError.self)
let propProducer = requestPropertyValue()
customerNoProducer
.combineLatest(with: propProducer)
.observe(on: UIScheduler())
.on(starting: { [weak self] _ in
if let strongSelf = self {
strongSelf.showLoadingOnView(strongSelf.view)
}
})
.startWithSignal { signal, _ in
signal.observeResult { [weak self] result in
if let strongSelf = self {
strongSelf.hideLoadingForView(strongSelf.view)
if let value = result.value {
strongSelf.customNo.value = value.0
strongSelf.generatedProdNo = value.0
strongSelf.tableView.reloadData()
}
}
}
}
}
combineLatest函数使多个信号都响应时才通知,不需要保留任何临时状态就优雅的解决了这种问题
再举个使用场景,对于搜索,假定我们需要针对用户的输入内容显示相关的匹配,这种情况如果用户没输入或删除一个字符就响应对用户来说太不友好了,
浪费网络流量,网络流量就是金钱啊,对服务端也是压力,这种时候就需要对客户端进行限流处理了,一般想到的方法就是用定时器加一堆判断逻辑,
我们知道定时器用不好就会导致内存泄漏,这种情况如果用RAC处理就简单的令人发指,开个玩笑说严重了,引用我在代码中的一段
searchField?.reactive
.continuousTextValues
.throttle(0.8, on: QueueScheduler.main)
.observeValues({ [unowned self] text in
self.handleSearchTextChange(self.searchField)
})
是不是很简单,好了,ReactiveCocoa的常用场景下的使用就讲到这里