【发布时间】:2021-12-01 14:17:00
【问题描述】:
我正在创建一个基本的 iOS 应用程序,我从一个包含图像的 API 中获取一组数据 (JSON)。我正在使用UIViewController 并有一个自定义UITableViewCell。
为了停止发送网络请求,我创建了一个缓存来存储<url: UIImage>。问题是为了将图像添加到缓存中,我将模型(网络)类传递给自定义UITableViewCell(视图)。
我的理解是视图应该不知道模型。这是 MVC 可接受的设计还是有办法解决这个问题?
摘要代码如下(现在使用字典作为缓存。稍后将更改为NSCache)
我还使用协议/委托在网络和视图控制器之间传递日期。
protocol ModelDelegate {
func dataFetched(_ data:[DataItem])
}
//This is the model(networking) class
class Model {
var delegate: ModelDelegate?
var imagecache: [String: UIImage] = [:]
func getData() {
let url = URL(string: Constants.DATA_URL)
guard url != nil else {
print("Invalid URL!")
return
}
let session = URLSession.shared.dataTask(with: url!) { data, response, error in
if error != nil && data == nil {
print("There was a data retriving error!")
return
}
let decoder = JSONDecoder()
do {
let response = try decoder.decode(Data.self, from: data!)
if response.data != nil {
let sorteddata = response.data!.sorted(by: { $0.data < $1.data })
DispatchQueue.main.async {
self.delegate?.dataFetched(sorteddata)
}
}
} catch {
print(error.localizedDescription)
}
}
session.resume()
}
}
//Custom UITableView Cell
class DataViewCell: UITableViewCell {
@IBOutlet weak var dataImage: UIImageView!
@IBOutlet weak var dataName: UILabel!
var model = Model()
var data: DataItem?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setCell(_ data: DataItem) {
self.data = data
self.dataName.text = data.strdata
guard self.data?.thumbnail != nil else {
return
}
if let imageData = model.imagecache[self.data!.thumbnail] {
print("using cache")
DispatchQueue.main.async {
self.DataImage.image = imageData
}
}
let url = URL(string: self.data!.thumbnail)
let session = URLSession.shared.dataTask(with: url!) { data, response, error in
if error == nil && data != nil {
let image = UIImage(data: data!)
self.model.imagecache[self.data!.thumbnail] = image
DispatchQueue.main.async {
self.DataImage.image = image
}
}
}
session.resume()
}
}
//View Controller
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, ModelDelegate {
@IBOutlet weak var tableView: UITableView!
var model = Model()
var data = [DataItem]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
model.delegate = self
model.getdata()
}
func dataFetched(_ data: [DataItem]) {
self.data = data
tableView.reloadData()
}
//TableView methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Constants.ID, for: indexPath) as! DataViewCell
let data = self.categories[indexPath.row]
cell.setCell(data)
return cell
}
}
【问题讨论】:
-
以上代码违反了Solid原则。 S -> 单一职责 最好为 URL 调用创建一个单独的 HttpUtility。最好在 cellForRowAt 索引路径中使用“模型”而不是 DataViewCell。
-
视图,包括 UITableViewCell,应该不知道网络逻辑或任何底层模型类型。如果您要坚持使用 MVC,则只有您的视图控制器应该进行网络调用。它负责模型、网络和视图之间的交互。另外,我建议重命名您的模型。模型只保存数据。更好的名称是 DataProvider 或 DataService。
标签: ios swift model-view-controller uikit