正确使用 RxSwift 和 TableView
Posted
技术标签:
【中文标题】正确使用 RxSwift 和 TableView【英文标题】:Correct usage of RxSwift with TableView 【发布时间】:2017-02-19 19:38:54 【问题描述】:我不知道如何在 ModelView 和 ViewController 之间传输数据。在
选择模型视图控制器
class SelectModelViewController: UIViewController
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var errorLabel: UILabel!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var markViewModel : MarkViewModel?
let markService = MarkService()
let disposeBag = DisposeBag()
override func viewDidLoad()
super.viewDidLoad()
markViewModel = MarkViewModel(markService: markService)
markViewModel?.data.asObservable()
.bindTo(tableView.rx.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) (_, element, cell) in
cell.textLabel?.text = element
.addDisposableTo(disposeBag)
MarkViewModel 有错误。我做错了什么
结构 MarkViewModel
let markService: MarkService
var data: Driver<[Mark]>
init(markService: MarkService)
self.markService = markService
data = markService.get()
.map result in
switch result
case.success(let marks):
return marks.map mark in
return mark
case .error(let error):
print(error)
.asDriver(onErrorJustReturn: .error(.other))
标记服务
结构标记服务
func get() -> Observable<Result<[Mark]>>
return URLSession.shared.rx.json(url: URL(string: API.BaseURL)!)
.retry(3)
.map
var marks = [Mark]()
guard let json = $0 as? [String: Any],
let items = json["RBMarks"] as? [[String : Any]] else
return .error(.badJSON)
for item in items
if let mark = Mark(json: item)
marks.append(mark)
else
return .error(.badJSON)
return .success(marks)
.catchErrorJustReturn(.error(.noInternet))
【问题讨论】:
您应该尝试提供一些细节来说明为什么这不起作用。出了什么问题,您预计会发生什么? @StefanDorunga 我只是不明白如何在 ModelView 和 ViewController 之间传输数据 【参考方案1】:首先,我们可以从MarkService
返回Observable<Result<[Mark]>>
,而不是Any
。这将有助于稍后显示它们。
struct MarkService
func get() -> Observable<Result<[Mark]>>
return URLSession.shared.rx.json(url: URL(string: API.BaseURL)!)
.retry(3)
.map
var marks = [Mark]()
guard let json = $0 as? [String: Any],
let items = json["RBMarks"] as? [[String : Any]] else
return .error(.badJSON)
for item in items
if let mark = Mark(json: item)
marks.append(mark)
else
return .error(.badJSON)
return .success(marks)
.catchErrorJustReturn(.error(.noInternet))
然后,让我们在MarkViewModel
中删除对data
的订阅。我们还将标记转换为更适合展示的内容。
struct MarkViewModel
let markService: MarkService
var data: Driver<[String]>
var marks: Variable<[Mark]>
let disposeBag = DisposeBag()
init(markService: MarkService)
self.markService = markService
data = markService.get()
.map result in
guard case .success(let marks) = result else
return ["Error while getting marks"]
return marks.map mark in
"For assignment \(mark.assignmentName), you were marked with \(mark.grade)/10"
.asDriver(onErrorJustReturn: .error(.other))
现在,在视图控制器中,我们可以使用 RxSwift 的表格视图绑定来显示这些数据
let disposeBag = DisposeBag()
func viewDidLoad()
viewModel.data
.bindTo(tableView.rx.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) (_, element, cell) in
cell.textLabel?.text = element
.addDisposableTo(disposeBag)
这显然只是一个示例,代码会根据特定视图的要求而改变。
【讨论】:
感谢您的回复!我从MarkService
返回通用枚举Result<Any>
处理程序错误。如果MarkService
将返回Result<Any>
,该代码将如何显示
Result
的强大之处其实在于我可以持有一个类型或者一个错误。所以这里不需要使用Any
。但如果你真的需要,你需要将视图控制器中的 guard
更改为 guard case .success(let anyMarks) = result, let marks = anyMarks as? [Mark] else
我编辑了问题,viewModel 中有错误Cannot assign value of type 'SharedSequence<DriverSharingStrategy, _>' to type 'SharedSequence<DriverSharingStrategy, [Mark]>' (aka 'SharedSequence<DriverSharingStrategy, Array<Mark>>')'
在视图模型中,将case .error(let error): print(error)
替换为case .error(let error): throw error
。以上是关于正确使用 RxSwift 和 TableView的主要内容,如果未能解决你的问题,请参考以下文章