Reactive Cocoa 5 和 ReactiveSwift 网络请求处理
Reactive Cocoa 5 and ReactiveSwift network requests handling
我正在尝试确定是否可以使用 ReactiveSwift 和 RAC5 实现适合我需求的网络请求处理。
在主题 下,有人告诉我可以用 SignalProducer 完成,但深入研究并没有给我预期的结果
所以,我想要:
1.每次textField中的文本变化发送请求(按关键字搜索)。
2. 一旦用户关闭当前ViewController,当前请求应该自动取消
3. 可以在关键字更改后取消请求
这是我的
self.textField.reactive.continuousTextValues.skipNil().filter({ (value) -> Bool in
return value.characters.count > 0
}).observeValues { [unowned self] (value) in
self.fetchSignalDisposable?.dispose()
self.fetchSignal = self.producerFor(keyword: value).on(started: {
print("started")
}, failed: { (error) in
print("error")
}, completed: {
print("completed")
}, value: { [unowned self] (items) in
print("value")
self.items.append(contentsOf: items)
self.tableView.reloadData()
})
self.fetchSignalDisposable = self.fetchSignal!.start()
}
这里是生产者初始化器
return SignalProducer<Any, NSError> { (observer, disposable) in
let task: URLSessionDataTask? = NetworkClient.fetchRequestWith(uri: "test", parameters: ["keyword" : keyword], success: { response in
observer.send(value: response)
observer.sendCompleted()
}, failure: { error in
observer.send(error: error)
observer.sendCompleted()
})
disposable += {
task?.cancel()
}
}
备注:
1. 有时我想要有点 "both handler block" 在成功和错误时都会被调用,所以像隐藏加载指示器这样的东西可以在那个块下完成。
这里很少problems/questions:
1. 一旦我关闭 VC(取消操作),就会再次调用 observeValue 处理程序。它可以通过添加 .skipRepeats()
来修复,但我想这只是一种解决方法,而不是确切的解决方案。如果我关闭 VC
,我不想再让这个观察者处于活动状态
2. completed
块不会在出错的情况下调用,即使我在调用 send(error: error)
后立即手动调用它
3. 如果请求仍在加载并且我关闭 VC,它不会被自动处理 ,这对我来说很奇怪。我认为一旦 viewController 失去对 signalProducer 的引用,就会自动调用 dispose 块。即使在 VC 的 deinit
方法中调用 self.fetchSignalDisposable?.dispose()
也不会取消请求。它仍然完成请求并调用 value
处理程序,这导致崩溃并出现 Bad Access 错误
我个人的需求是:
1. 有某种 "both" 块,在请求
成功和失败后都会被调用
2. 一旦我关闭 VC
,必须删除所有文本字段文本值的观察者并且不再激活
3. 网络请求必须在我关闭时立即取消 VC
P.S.: 当然,感谢所有阅读这篇文章post并花时间帮助我的人!
ReactiveSwift readme 中的 "Making network requests" 示例是此类事情的一个很好的例子。与其在您的文本字段信号上使用 observeValues
,通常您会像这样使用 .flatMap(.latest)
将其直接连接到您的 SignalProducer(请注意,我没有检查过这段代码,但希望它能理解这个想法):
self.textField.reactive.continuousTextValues
.skipNil()
.filter { (value) -> Bool in
return value.characters.count > 0
}
.flatMap(.latest) { [unowned self] value in
return self.producerFor(keyword: value)
// Handling the error here prevents errors from terminating
// the outer signal. Now a request can fail while allowing
// subsequent requests to continue.
.flatMapError { error in
print("Network error occurred: \(error)")
return SignalProducer.empty
}
}
.observe(on: UIScheduler())
.observe { [unowned self] event in
switch event {
case let .value(items):
print("value")
self.items.append(contentsOf: items)
self.tableView.reloadData()
case let .failed(error):
print("error")
case .completed, .interrupted:
print("completed")
}
}
指定.latest
会导致在新的网络请求启动时自动取消先前的网络请求,因此无需在全局变量中跟踪当前请求。
至于管理生命周期,如果不了解更广泛的代码结构,就很难说什么是最好的。通常我会在我的信号中添加类似 .take(during: self.reactive.lifetime)
的内容以在 self
被解除分配时终止订阅,可能就在调用 observe
.
之前
错误事件终止信号。发生错误后无需发送已完成的事件,观察者也不会看到它。基本上,complete 表示信号成功终止,而 error 表示信号失败终止。
我正在尝试确定是否可以使用 ReactiveSwift 和 RAC5 实现适合我需求的网络请求处理。
在主题
所以,我想要:
1.每次textField中的文本变化发送请求(按关键字搜索)。
2. 一旦用户关闭当前ViewController,当前请求应该自动取消
3. 可以在关键字更改后取消请求
这是我的
self.textField.reactive.continuousTextValues.skipNil().filter({ (value) -> Bool in
return value.characters.count > 0
}).observeValues { [unowned self] (value) in
self.fetchSignalDisposable?.dispose()
self.fetchSignal = self.producerFor(keyword: value).on(started: {
print("started")
}, failed: { (error) in
print("error")
}, completed: {
print("completed")
}, value: { [unowned self] (items) in
print("value")
self.items.append(contentsOf: items)
self.tableView.reloadData()
})
self.fetchSignalDisposable = self.fetchSignal!.start()
}
这里是生产者初始化器
return SignalProducer<Any, NSError> { (observer, disposable) in
let task: URLSessionDataTask? = NetworkClient.fetchRequestWith(uri: "test", parameters: ["keyword" : keyword], success: { response in
observer.send(value: response)
observer.sendCompleted()
}, failure: { error in
observer.send(error: error)
observer.sendCompleted()
})
disposable += {
task?.cancel()
}
}
备注:
1. 有时我想要有点 "both handler block" 在成功和错误时都会被调用,所以像隐藏加载指示器这样的东西可以在那个块下完成。
这里很少problems/questions:
1. 一旦我关闭 VC(取消操作),就会再次调用 observeValue 处理程序。它可以通过添加 .skipRepeats()
来修复,但我想这只是一种解决方法,而不是确切的解决方案。如果我关闭 VC
,我不想再让这个观察者处于活动状态
2. completed
块不会在出错的情况下调用,即使我在调用 send(error: error)
后立即手动调用它
3. 如果请求仍在加载并且我关闭 VC,它不会被自动处理 ,这对我来说很奇怪。我认为一旦 viewController 失去对 signalProducer 的引用,就会自动调用 dispose 块。即使在 VC 的 deinit
方法中调用 self.fetchSignalDisposable?.dispose()
也不会取消请求。它仍然完成请求并调用 value
处理程序,这导致崩溃并出现 Bad Access 错误
我个人的需求是:
1. 有某种 "both" 块,在请求
成功和失败后都会被调用
2. 一旦我关闭 VC
,必须删除所有文本字段文本值的观察者并且不再激活
3. 网络请求必须在我关闭时立即取消 VC
P.S.: 当然,感谢所有阅读这篇文章post并花时间帮助我的人!
ReactiveSwift readme 中的 "Making network requests" 示例是此类事情的一个很好的例子。与其在您的文本字段信号上使用 observeValues
,通常您会像这样使用 .flatMap(.latest)
将其直接连接到您的 SignalProducer(请注意,我没有检查过这段代码,但希望它能理解这个想法):
self.textField.reactive.continuousTextValues
.skipNil()
.filter { (value) -> Bool in
return value.characters.count > 0
}
.flatMap(.latest) { [unowned self] value in
return self.producerFor(keyword: value)
// Handling the error here prevents errors from terminating
// the outer signal. Now a request can fail while allowing
// subsequent requests to continue.
.flatMapError { error in
print("Network error occurred: \(error)")
return SignalProducer.empty
}
}
.observe(on: UIScheduler())
.observe { [unowned self] event in
switch event {
case let .value(items):
print("value")
self.items.append(contentsOf: items)
self.tableView.reloadData()
case let .failed(error):
print("error")
case .completed, .interrupted:
print("completed")
}
}
指定.latest
会导致在新的网络请求启动时自动取消先前的网络请求,因此无需在全局变量中跟踪当前请求。
至于管理生命周期,如果不了解更广泛的代码结构,就很难说什么是最好的。通常我会在我的信号中添加类似 .take(during: self.reactive.lifetime)
的内容以在 self
被解除分配时终止订阅,可能就在调用 observe
.
错误事件终止信号。发生错误后无需发送已完成的事件,观察者也不会看到它。基本上,complete 表示信号成功终止,而 error 表示信号失败终止。