使用 RxSwift 在网络请求后更新 SwiftUI 列表
Posted
技术标签:
【中文标题】使用 RxSwift 在网络请求后更新 SwiftUI 列表【英文标题】:Update SwiftUI List after network request using RxSwift 【发布时间】:2019-12-20 12:28:35 【问题描述】:发出网络请求后,我需要更新 SwiftUI 列表。对于请求,我使用 Moya 方法和触发器组合(输入和输出 - “Kickstarter”)。 由于项目的结构,我不能使用组合框架,虽然他们有很多有用的建议(不确定我的情况)。
简单的联系人列表:
struct ContactList: View
var viewModel: UserViewModel
var body: some View
NavigationView
List(viewModel.users) contact in
NavigationLink(destination: ContactDetail(user: contact))
ContactRow(user: contact)
.navigationBarTitle(Text("Team Members"))
然后是视图模型
class UserViewModel
let disposeBag = DisposeBag()
var users: [TeamMember] = []
init(users: [TeamMember] = [])
let networkModel = UserNetworkModel()
networkModel.output.teamMembers.subscribe (event) in
self.users.append(contentsOf: event.element.orEmpty)
.disposed(by: disposeBag)
networkModel.output.error.subscribe(onNext: error in
print(error.localizedDescription)
).disposed(by: disposeBag)
networkModel.input.loadTrigger.onNext(Void())
self.users = users
和网络模型
class UserNetworkModel
let disposeBag = DisposeBag()
let input: Input
let output: Output
struct Input
let loadTrigger: AnyObserver<Void>
let searchTrigger: AnyObserver<String>
struct Output
let teamMembers: Observable<[TeamMember]>
let error: Observable<Error>
internal let loadSubject = PublishSubject<Void>()
internal let searchSubject = BehaviorSubject<String>(value: "")
internal let errorSubject = PublishSubject<Error>()
internal let teamMembersSubject = BehaviorSubject<[TeamMember]>(value: [])
init()
let service = MoyaProvider<TeamTarget>()
self.input = Input(loadTrigger: loadSubject.asObserver(), searchTrigger: searchSubject.asObserver())
self.output = Output(teamMembers: teamMembersSubject.asObservable(), error: errorSubject.asObservable())
let result = loadSubject.flatMapLatest _ -> Observable<[TeamMember]> in
service.rx.request(.get).debug().mapArray(TeamMember.self).asObservable()
.share(replay: 1)
Observable.combineLatest(result, searchSubject).map (arg) in
let (members, filter) = arg
if filter.isEmpty
return members
else
let searchText = try! self.searchSubject.value()
return members.filter(
return [$0.firstName, $0.lastName]
.compactMap( $0 )
.first(where: $0.hasPrefix(searchText) ) != nil
)
.bind(to: teamMembersSubject).disposed(by: disposeBag)
result.subscribe(onError: error in
self.errorSubject.onNext(error)
).disposed(by: self.disposeBag)
是否可以通过这种方式更新用户数组?还是只有Combine可以轻松为我做到? 感谢您的宝贵时间。
【问题讨论】:
【参考方案1】:虽然我找到了一些组合解决方案。 仍在等待 Rx 解决方案。 所以,我修复了它,只是为 ContactList 属性添加了@ObservedObject,为网络模型中的用户数组添加了@Published。更少的代码,本机但不是我想要的。
完整答案:
struct ContactList: View
@ObservedObject var networkModel: NetworkModel
var body: some View
NavigationView
List(networkModel.users) contact in
NavigationLink(destination: ContactDetail(user: contact))
ContactRow(user: contact)
.navigationBarTitle(Text("Team Members"))
#if DEBUG
struct ContactList_Previews: PreviewProvider
static var previews: some View
ContactList(networkModel: .init(users: contactData))
#endif
class NetworkModel: ObservableObject
@Published var users = [User]()
init(users: [User] = [])
getMembers()
private func getMembers()
let provider = MoyaProvider<TeamTarget>()
provider.request(.get) [weak self] (result) in
switch result
case .success(let response):
do
let result = try JSONDecoder().decode([User].self, from: response.data)
self?.users.append(contentsOf: result)
catch
print(error.localizedDescription)
case .failure(let error):
print(error.errorDescription.orEmpty)
【讨论】:
以上是关于使用 RxSwift 在网络请求后更新 SwiftUI 列表的主要内容,如果未能解决你的问题,请参考以下文章