在UICollectionView中从API加载图片URL数组的问题求助
问题分析与修复方案
核心问题梳理
- 数据模型数组定义错误:原代码用
[Welcome]存储数据,但实际需要的是Welcome结构体里的[Location]数组,数组类型定义错误导致无法正确访问图片地址。 - API请求位置错误:把网络请求放在
cellForItemAt中,会导致每个cell显示时重复发起API请求,既浪费资源,还会因cell复用导致图片显示混乱。 - URL语法错误:原API地址字符串末尾多了一个
),导致URL(string:)创建失败,直接引发崩溃。 - 图片加载方式错误:用
try? Data(contentsOf:)同步加载图片,会阻塞后台线程影响性能,且未处理cell复用问题。 - 未设置CollectionView代理:
viewDidLoad中未给collectionView设置delegate和dataSource,可能导致数据源方法不执行。
修正后的完整代码
ViewController代码
import UIKit struct Welcome: Decodable { let images: [Location] } struct Location: Decodable { let imageloc: String } class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { // 修正:存储Location数组,对应API返回的images列表 var imageLocations: [Location] = [] @IBOutlet weak var collectionView: UICollectionView! override func viewDidLoad() { super.viewDidLoad() // 设置代理和数据源 collectionView.delegate = self collectionView.dataSource = self // 发起API请求获取数据 fetchImageData() } // 单独封装API请求方法 private func fetchImageData() { // 修正URL:去掉末尾多余的`)` guard let url = URL(string: "http://swaminarayanwales.org.uk/DailyDarshan/ExportJsonV2.php?sMandir=Nairobi-Temple&Target=real&sm=sm") else { print("无效的API地址") return } URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } if let error = error { print("请求错误:\(error.localizedDescription)") return } guard let data = data else { print("未获取到数据") return } do { let welcomeData = try JSONDecoder().decode(Welcome.self, from: data) // 保存获取到的图片地址数组 self.imageLocations = welcomeData.images // 回到主线程刷新CollectionView DispatchQueue.main.async { self.collectionView.reloadData() } } catch { print("解析错误:\(error.localizedDescription)") } }.resume() } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { // 返回图片地址数组的数量 return imageLocations.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell // 先设置默认图片,避免复用显示旧内容 cell.imageView.image = UIImage(systemName: "photo") let location = imageLocations[indexPath.row] guard let imgUrl = URL(string: location.imageloc) else { print("无效的图片地址:\(location.imageloc)") return cell } // 异步加载图片,处理cell复用问题 URLSession.shared.dataTask(with: imgUrl) { [weak cell] data, _, error in if let error = error { print("图片加载错误:\(error.localizedDescription)") return } guard let data = data, let image = UIImage(data: data) else { return } DispatchQueue.main.async { // 确保cell未被复用才设置图片 if let currentCell = cell, currentCell == collectionView.cellForItem(at: indexPath) { currentCell.imageView.image = image } } }.resume() return cell } }
CollectionViewCell代码(无需修改,需确认IBOutlet关联正确)
import UIKit class CollectionViewCell: UICollectionViewCell { @IBOutlet weak var imageView: UIImageView! }
关键修改说明
- 修正数据存储数组:将
var imageloc = [Welcome]()改为var imageLocations: [Location] = [],直接存储API返回的图片地址列表,方便后续访问imageloc属性。 - API请求移至viewDidLoad:单独封装
fetchImageData方法,页面加载时仅发起一次请求,获取数据后刷新CollectionView,避免重复请求。 - 修复URL错误:移除原URL末尾多余的
),确保URL能正确创建。 - 优化图片加载:用
URLSession异步加载图片,通过判断当前cell是否仍对应原indexPath,避免cell复用导致图片显示错位;同时设置默认图片提升用户体验。 - 设置CollectionView代理:在
viewDidLoad中添加collectionView.delegate = self和collectionView.dataSource = self,确保数据源方法正常执行。
内容的提问来源于stack exchange,提问作者heli bhadeshiya
相关产品推荐
相关产品推荐

