MVVM是ios中编程经常会用到的格式,MVVM大致主要分为三个部分,第一个Model,模型,把会用到的数据模型建立出来,第二个是View,视图,基本上就是viewController,第三个是ViewModel,视图模型,一般是写需要在视图上展示背后的逻辑
首先是Model
import Foundation
struct StructFashion: Decodable {
let hits: [HitsContainer]
}
struct HitsContainer: Decodable {
let largeImageURL: String
let likes: Int
let views: Int
let type: String
}
这里我会用到一个关于fashion的url
https://pixabay.com/api/?key=13544198-1e8b7d38bdf44ee4a254099f5&category=fashion
在hitContainer这个array中,有largeImageURL,也就是一会我会用到这个url来下载图片
接下来是viewModel
import Foundation
class ViewModel: ViewModelProtocol {
private var hitsContainer: [HitsContainer] = []{
didSet{
updateCallBack()
}
}
var updateCallBack: ()-> Void
init(updateCallBack: @escaping ()-> Void) {
self.updateCallBack = updateCallBack
}
func loadData() {
let urlString = "https://pixabay.com/api/?key=13544198-1e8b7d38bdf44ee4a254099f5&category=fashion"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
if let error = error {
print(error, "loadData error")
}
guard let jsonObject = try? JSONDecoder().decode(StructFashion.self, from: data).hits else { return }
self.hitsContainer = jsonObject
}.resume()
}
func getObject()-> [HitsContainer] {
return hitsContainer
}
func getViewModel(index: Int) -> ViewModelGetObject {
return ViewModelGetObject(hitsContainer: hitsContainer[index])
}
}
protocol ViewModelProtocol {
func loadData()
func getObject()-> [HitsContainer]
func getViewModel(index: Int) -> ViewModelGetObject
}
这里我用了protocol的格式,方便一会使用,需要注意的是在getViewModel这个function中,我还需要建 第二个ViewModel,ViewModelGetObject, 用来下载图片
import Foundation
import UIKit
struct ViewModelGetObject {
private let hitsContainer: HitsContainer
init(hitsContainer: HitsContainer) {
self.hitsContainer = hitsContainer
}
func loadType() -> String {
return hitsContainer.type
}
func loadImage(completion: @escaping(UIImage?) -> Void) {
let urlString = hitsContainer.largeImageURL
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, _, error) in
guard let data = data else { return }
let image = UIImage(data: data)
completion(image)
}.resume()
}
}
这是第二个viewModel,我给它命名ViewModelGetObject,主要用来下载图片和得到hitContainer里的type这个string
下面是View里的cell,主要用来展示tableView里每一格需要展示的object
import UIKit
class TableViewCell: UITableViewCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var fashionImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func configure(viewModelGetObject: ViewModelGetObject?) {
self.nameLabel.text = viewModelGetObject?.loadType()
viewModelGetObject?.loadImage { (image) in
DispatchQueue.main.async {
self.fashionImage.image = image
}
}
}
}
我这里只展示了模型里的type和对应的图片,用一个configure,配置的function进行封装,最后是viewController
import UIKit
class ViewController: UIViewController {
var viewModel: ViewModelProtocol?
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")
let updateCallBack: () -> Void = {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
viewModel = ViewModel(updateCallBack: updateCallBack)
viewModel?.loadData()
}
}
extension ViewController: UITableViewDelegate {
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel?.getObject().count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
cell.configure(viewModelGetObject: viewModel?.getViewModel(index: indexPath.row))
return cell
}
}
因为我单独建立了一个tableviewCell的文件,所以需要viewDidload进行register,需要注意最后
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
这个function
这里我只需要把封装好的configure function拿在这里直接用就可以展示图片和文字信息
最后是效果图
Github
https://github.com/grm121616/MVVMLoadImageExample/tree/master/MVVMPractice