在另一个创建 rxswift 中订阅单个可观察量



我想从服务器获取数据并更新我的数据库,然后向用户显示接收的数据。为了这个目标,我在我的视图模型中有一个方法(getData()),它返回一个Single我在视图控制器(myVC.getData.subscribe({single in ...}))中调用并订阅此方法 在此方法中,首先我调用和订阅(getUnread()->Single) 该方法运行,但我无法获得单个事件,我不明白为什么我无法在回调中获取事件

之后我想用调用保存数据(保存([Moddel])->单)

//I removed some part of this code it was to big
//This method is View Model
func getData() -> Single<[Model]> {
return Single<[Model]>.create {[weak self] single in
//#1
self!.restRepo.getUnread().subscribe({ [weak self] event in
//#4
switch event {
case .success(let response):
let models = response
//#2
self!.dbRepo.save(issues!).subscribe({ event in
switch event {
case .success(let response):
let models = response
single(.success(models))
case .error(let error):
single(.error(error))
}
}).disposed(by: self!.disposeBag)
case .error(let error):
single(.error(error))
}
}).disposed(by: self!.disposeBag)
return Disposables.create()
}
}

. .

//I removed some part of this code it was to big
//This method is in RestRepo class
func getUnread() -> Single<[Model]> {

return Single<[Model]>.create { single in
let urlComponent = ApiHelper.instance.dolphinURLComponents(for: ApiHelper.ISSUES_PATH)
var urlRequest = URLRequest(url: urlComponent.url!)
ApiHelper.instance.alamofire.request(urlRequest).intercept().responseJSON { response in
debugPrint(response)
let statusCode = response.response?.statusCode
switch statusCode {
case 200:
do {
let models = try JSONDecoder().decode([Model].self, from: response.data!)
//#3
single(.success(models))
}catch{
print(error)
}
case 304:
debugPrint(response)
default:
single(.error(IssueResponseStatusCodeError(code: statusCode ?? 0)))
}
}
return Disposables.create()
}

首先,你需要改变你的想法。您无需在应用程序中执行任何操作。充其量,你布置了可观察链(它不再做任何事情,就像水管">"某事一样。然后你启动应用程序,让"水"流动。

因此,考虑到这一点,让我们检查一下您的问题:

我想从服务器获取数据...

并不是"你"想要获取数据。该请求是由于用户的某些操作(可能是按钮点击)或其他一些副作用而发出的。那是什么动作?这需要在代码中表达。对于以下内容,我将假设这是一个按钮点击。这意味着您应该拥有:

class Example: UIViewController {
var button: UIButton!
var restRepo: RestRepo!
override func viewDidLoad() {
super.viewDidLoad()
let serverResponse = button.rx.tap
.flatMapLatest { [restRepo] in
restRepo!.getUnread()
.map { Result<[Model], Error>.success($0) }
.catchError { .just(Result<[Model], Error>.failure($0)) }
}
.share(replay: 1)
}
}
protocol RestRepo {
func getUnread() -> Observable<[Model]>
}
struct ProductionRestRepo: RestRepo {
func getUnread() -> Observable<[Model]> {
let urlComponent = ApiHelper.instance.dolphinURLComponents(for: ApiHelper.ISSUES_PATH)
let urlRequest = URLRequest(url: urlComponent.url!)
return URLSession.shared.rx.data(request: urlRequest)
.map { try JSONDecoder().decode([Model].self, from: $0) }
}
}
class ApiHelper {
static let ISSUES_PATH = ""
static let instance = ApiHelper()
func dolphinURLComponents(for: String) -> URLComponents { fatalError() }
}
struct Model: Decodable { }

这里要注意的是,getUnread()是由button.rx.tap引起的效果 .上面建立了一个因果链。

你的问题继续说"你"想要:

。更新我的数据库...

在这里,原因是网络请求,效果是数据库保存,所以我们只需要将其添加到viewDidLoad中(注意下面的代码使用RxEnumKit)。

let dbResponse = serverResponse
.capture(case: Result.success)
.flatMapLatest { [dbRepo] models in
dbRepo!.save(models)
.map { Result<Void, Error>.success(()) }
.catchError { .just(Result<Void, Error>.failure($0)) }
}

您的问题还说"您"想要:

。向用户显示接收的数据。

请注意,向用户显示接收的数据与数据库保存无关。它们是两个可以并行完成的独立操作。

向用户显示接收到的数据以 serverResponse 作为原因,以显示作为结果。

serverResponse
.capture(case: Result.success)
.subscribe(onNext: { models in
print("display the data to the user.", models)
})
.disposed(by: disposeBag)

最后,你没有提到它,但你也必须处理错误:

因此,将其也添加到viewDidLoad中:

Observable.merge(serverResponse.capture(case: Result.failure), dbResponse.capture(case: Result.failure))
.subscribe(onNext: { error in
print("an error occured:", error)
})
.disposed(by: disposeBag)

下面的代码是上述所有代码,作为一个块。这编译得很好...

import UIKit
import RxSwift
import RxCocoa
import EnumKit
import RxEnumKit
extension Result: CaseAccessible { }
class Example: UIViewController {
var button: UIButton!
var restRepo: RestRepo!
var dbRepo: DBRepo!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let serverResponse = button.rx.tap
.flatMapLatest { [restRepo] in
restRepo!.getUnread()
.map { Result<[Model], Error>.success($0) }
.catchError { .just(Result<[Model], Error>.failure($0)) }
}
.share(replay: 1)
let dbResponse = serverResponse
.capture(case: Result.success)
.flatMapLatest { [dbRepo] models in
dbRepo!.save(models)
.map { Result<Void, Error>.success(()) }
.catchError { .just(Result<Void, Error>.failure($0)) }
}
serverResponse
.capture(case: Result.success)
.subscribe(onNext: { models in
print("display the data to the user.", models)
})
.disposed(by: disposeBag)
Observable.merge(serverResponse.capture(case: Result.failure), dbResponse.capture(case: Result.failure))
.subscribe(onNext: { error in
print("an error occured:", error)
})
.disposed(by: disposeBag)
}
}
protocol RestRepo {
func getUnread() -> Observable<[Model]>
}
protocol DBRepo {
func save(_ models: [Model]) -> Observable<Void>
}
struct ProductionRestRepo: RestRepo {
func getUnread() -> Observable<[Model]> {
let urlComponent = ApiHelper.instance.dolphinURLComponents(for: ApiHelper.ISSUES_PATH)
let urlRequest = URLRequest(url: urlComponent.url!)
return URLSession.shared.rx.data(request: urlRequest)
.map { try JSONDecoder().decode([Model].self, from: $0) }
}
}
class ApiHelper {
static let ISSUES_PATH = ""
static let instance = ApiHelper()
func dolphinURLComponents(for: String) -> URLComponents { fatalError() }
}
struct Model: Decodable { }

我希望所有这些都对您有所帮助,或者至少会产生更多问题。

最新更新