如何在 swift 结构初始化程序中添加网络获取
我试图从 URL(第一个网络调用)获取数据,然后进行第二个网络调用以从第一个响应中的 url 获取图像,并快速显示在表格视图上。
第一个网络调用的 json 包含 3 个字符串:
struct Item: Codable {
var title: String?
var image_url: String?
var content: String
}
我需要做的是,在 json 解码并获取此 [Item]
数组之后,我还需要对其中的每个项目进行网络调用,以便我可以还获取每个单元格的 UIImage 并在每个单元格上显示标题、内容和图像。
我的问题是,进行网络调用(以 MVVM 模式)的最佳位置在哪里?
我的第一个想法是在 TableViewCell
中:
func configCell(item: Item) {
titleLabel.text = item.title
descriptionLable.text = item.content
// fetch image
service.fetchImage(with: item.image_url) { result in
switch result {
case .success(let image):
DispatchQueue.main.async { [weak self] in
if let image = image {
self?.iconView.isHidden = false
}
}
case .failure(let error):
print(error.localizedDescription)
return
}
}
}
但是,我不确定这是否是正确的方法/位置,因为它可能会导致错误的图像附加到每个单元格。它还将网络层耦合到视图层。
所以我的第二个想法是,在 viewModel 中创建第二个模型并在其中进行网络调用:
struct ImageItem: Codable {
var title: String?
var image_url: String?
var content: String
var image: Data?
init(with item: Item) {
self.title = item.title
self.content = item.content
ContentService().fetchImage(with: item.image_url) { result in
switch result {
case .success(let image):
self.image = image?.pngData()
case .failure(let error):
print(error.localizedDescription)
}
}
}
但这也感觉不对。似乎我也无法在结构初始值设定项中进行网络调用。
有人可以帮助我或给我关于在哪里放置第二层网络调用来获取图像的建议吗?
I'm trying to get data from an URL (1st network call), then make a 2nd network call to fetch image from the url in the first response, and present on tableview in swift.
The json from 1st network call contains 3 strings:
struct Item: Codable {
var title: String?
var image_url: String?
var content: String
}
What I need to do is, after json decoding and get this [Item]
array, I also need to make network call for each item in it so I can also get the UIImage
for each of them and present title, content and Image
on each cell.
My question is, where is the best place to make the network call (in MVVM pattern)?
My first thought is in the TableViewCell
:
func configCell(item: Item) {
titleLabel.text = item.title
descriptionLable.text = item.content
// fetch image
service.fetchImage(with: item.image_url) { result in
switch result {
case .success(let image):
DispatchQueue.main.async { [weak self] in
if let image = image {
self?.iconView.isHidden = false
}
}
case .failure(let error):
print(error.localizedDescription)
return
}
}
}
However, I'm not sure if this the right way/place to do so because it might cause wrong image attach to each cell. Also it couples network layer into view layer.
So my 2nd thought is, create a second model in the viewModel and make network call in it:
struct ImageItem: Codable {
var title: String?
var image_url: String?
var content: String
var image: Data?
init(with item: Item) {
self.title = item.title
self.content = item.content
ContentService().fetchImage(with: item.image_url) { result in
switch result {
case .success(let image):
self.image = image?.pngData()
case .failure(let error):
print(error.localizedDescription)
}
}
}
But that doesn't feel right either. Also seems like I can't make network call in struct initializer.
Could anyone help or give me advice about where to put this 2nd layer network call for fetching the image?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果这些图像轻量级,则可以直接在
CellForrow(at:)
uitableviewDataSource
的方法中进行操作。如果使用图书馆/豆荚(例如翠鸟) - 只有1行可以照顾好库:否则,您可能必须照顾好自己的缓存,除非真正需要的图像等,否则不要下载图像等
。由于图像下载/配置是在UiviewController中完成的,而不是在自定义单元格内完成,因此应该很好。但是,仍然确保您使用一些协议和单独的存储库类实现该协议并包含图像下载功能,因为视图控制器应该更像一个调解人,而不是加载过多的代码,例如网络和业务逻辑(VCS应该ACT ACT更像是视图,一般来说,为您的自定义单元格获取远程映像不是他们的工作,而是对于更简单的应用程序,除非您想过度设计内容,否则应该可以。
有人认为,视图模型应该是轻量重量,因此结构构成,而另一些人则将其逐步化,并添加了许多功能,例如与外部服务互动。这完全取决于您使用的MVVM的变化。我个人更喜欢将URL属性保存在视图模型中,并实现“ getRemoteImage(url :)”一部分,但我已经看到人们直接将UIImage属性直接添加到视图模型或数据类型属性并拥有一些转换器注入转换
数据 - > uiimage
。实际上,您可以拥有一个存储库,并将网络代码注入视图模型,然后添加观察者< uiimage?>在视图模型内部并通过封闭将相应的单元格的图像绑定到这些属性,因此该单元在成功下载(如果仍然可见)或下次出现在屏幕上时自动更新自己...因为每个单元格都会具有相应的视图模型 - 每个视图模型是否已经下载了Indexpath的图像,可以跟踪跟踪。
If those images are lightweight, you can do it directly inside
cellForRow(at:)
method ofUITableViewDataSource
. If using a library/pod such as Kingfisher - it's just 1 line that takes care of of, plus another one to import the library:Otherwise, you may have to take care yourself of caching, not downloading images unless really needed etc.
As long as the image download/configuration is done in UIViewController and not inside the Custom Cell, it should be all good. But still make sure you use some protocol and separate Repository class implementing that protocol and containing the image download functionality, because the View Controller should be more like a Mediator and not be loaded with too much code such as networking and business logic (VCs should act more like view, and generally speaking it's not their job to get the remote image for your custom cells, but for simpler apps that should be ok, unless you want to over-engineer things :) ).
Some people argue that View Models should be light weight and therefore structs, while others make them classes and add lots of functionality such as interacting with external service. It all depends of what variation of MVVM you are using. Personally I prefer to simply keep a URL property in the View Model and implement the "getRemoteImage(url:)" part outside the custom cell, but I've seen people adding UIImage properties directly to the View Models or Data type properties and having some converters injected that transform
Data -> UIImage
.You can actually have a Repository and inject the Networking code to the View Model, and then add an Observer<UIImage?> inside the View Model and bind the corresponding cells' images to those properties via closures so the cell automatically updates itself on successful download (if still visible) or next time it appears on screen... Since each cell would have a corresponding view model - each individual view model can keep track if the image for IndexPath was already dowloaded or not.