gpt4 book ai didi

ios - 使用 ReactiveCocoa (4.2.1) 和 Swift 异步加载图像

转载 作者:搜寻专家 更新时间:2023-11-01 07:22:26 25 4
gpt4 key购买 nike

我是第一次将 ReactiveCocoa 与 Swift 结合使用的初学者。我正在构建一个显示电影列表的应用程序,并且我正在使用 MVVM 模式。我的 ViewModel 看起来像这样:

class HomeViewModel {

let title:MutableProperty<String> = MutableProperty("")
let description:MutableProperty<String> = MutableProperty("")
var image:MutableProperty<UIImage?> = MutableProperty(nil)

private var movie:Movie

init (withMovie movie:Movie) {

self.movie = movie

title.value = movie.headline
description.value = movie.description

Alamofire.request(.GET, movie.pictureURL)
.responseImage { response in

if let image = response.result.value {
print("image downloaded: \(image)")
self.image.value = image
}
}

}
}

我想像这样在 UITableView 中配置我的单元格:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCellWithIdentifier("MovieCell", forIndexPath: indexPath) as! MovieCell
let movie:Movie = movieList[indexPath.row]
let vm = HomeViewModel(withMovie: movie)

// fill cell with data
vm.title.producer.startWithNext { (newValue) in
cell.titleLabel.text = newValue
}

vm.description.producer.startWithNext { (newValue) in
cell.descriptioLabel.text = newValue
}

vm.image.producer.startWithNext { (newValue) in
if let newValue = newValue {
cell.imageView?.image = newValue as UIImage
}
}

return cell
}

这是 Reactive Cocoa 的正确方法吗?我是否需要将标题和描述声明为可变的或只是图像(唯一改变的)。我想我可以使用绑定(bind),但我不确定如何继续。

最佳答案

要使用 Reactive Cocoa + MVVM 模式来做到这一点,我会首先将所有逻辑从其 View 模型移动到单元类本身来配置单元格。然后从 viewModel 中删除 MutableProperties(它们实际上不是可变的,我们不需要这些信号)。并且对于图像公开一个信号生成器,它将执行网络请求以在调用 start() 时获取图像,而不是在调用 init 时隐式获取它ViewModel,给我们类似的东西

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MovieCell", forIndexPath: indexPath) as! MovieCell
cell.viewModel = self.viewModelForIndexPath(indexPath)
return cell
}

private func viewModelForIndexPath(indexPath: NSIndexPath) -> MovieCellViewModel {
let movie: Movie = movieList[indexPath.row]
return HomeViewModel(movie: movie)
}

然后

class MovieCell: UITableViewCell
@IBOutlet weak var titleLabel: UILabel
@IBOutlet weak var descriptionLabel: UILabel
@IBOutlet weak var imageView: UIImageView

var viewModel: MovieCellViewModel {
didSet {
self.configureFromViewModel()
}
}

private func configureFromViewModel() {
self.titleLabel.text = viewModel.title
self.descriptionLabel.text = viewModel.description
viewModel.fetchImageSignal()
.takeUntil(self.prepareForReuseSignal()) //stop fetching if cell gets reused
.startWithNext { [weak self] image in
self?.imageView.image = image
}
}

//this could also go in a UITableViewCell extension if you want to use it other places
private func prepareForReuseSignal() -> Signal<(), NoError> {
return Signal { observer in
self.rac_prepareForReuseSignal // reactivecocoa builtin function
.toSignalProducer() // obj-c RACSignal -> swift SignalProducer
.map { _ in () } // AnyObject? -> Void
.flatMapError { _ in .empty } // NSError -> NoError
.start(observer)
}
}
}

在 ViewModel 中

struct HomeViewModel {
private var movie: Movie

var title: String {
return movie.headline
}

var description: String {
return movie.description
}

func fetchImageSignal() -> SignalProducer<UIImage, NSError> {
return SignalProducer { observer, disposable in
Alamofire.request(.GET, movie.pictureURL)
.responseImage { response in
if let image = response.result.value {
print("image downloaded: \(image)")
observer.sendNext(image) //send the fetched image on the signal
observer.sendCompleted()
} else {
observer.sendFailed( NSError(domain: "", code: 0, userInfo: .None)) //send your error
}
}
}
}

关于ios - 使用 ReactiveCocoa (4.2.1) 和 Swift 异步加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38112957/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com