IOS swift:用MVVM格式下载和展示图片

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值