如何创建自定义UICollectionViewDelegate/DataSource并解决方法不调用问题
问题根因
- 初始化顺序错误:你在创建collectionView时
customDataSource还未完成初始化,此时给cv.dataSource赋值的是nil,后续初始化customDataSource后没有重新给collectionView的dataSource赋值,导致数据源始终为空。 - 缺少UICollectionView必需的布局参数:你创建UICollectionView时只传入了frame,没有传入布局对象,会导致collectionView无法正常渲染内容。
- 数据源方法不完整:你自定义的CustomDataSource没有实现必需的
collectionView(_:cellForItemAt:)方法,就算数据源被调用也无法生成cell。 - 更新数据后没有刷新:调用
fill方法更新数据源后,没有主动触发collectionView的reloadData,新数据无法同步到视图。
修复方案
1. 调整MyController的初始化顺序,补充必要配置
final class MyController: UIViewController { private lazy var collectionView = methodCreatesCollectionView() private var items: [String]? private var customDataSource: CustomDataSource? init() { super.init(nibName: nil, bundle: nil) // 先初始化数据源,再创建collectionView customDataSource = CustomDataSource(parent: self) view.addSubview(collectionView) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func fill(with items: [String]) { self.items = items // 数据更新后主动刷新列表 collectionView.reloadData() } func methodCreatesCollectionView() -> UICollectionView { // 补充UICollectionView必需的布局配置,这里用流布局举例 let layout = UICollectionViewFlowLayout() layout.itemSize = CGSize(width: view.bounds.width, height: 60) layout.minimumLineSpacing = 8 let cv = UICollectionView(frame: view.bounds, collectionViewLayout: layout) // 此时customDataSource已初始化,赋值有效 cv.dataSource = customDataSource // 注册cell,后续生成cell时需要用到 cv.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "DefaultCell") return cv } }
2. 补全CustomDataSource的必需方法
private class CustomDataSource: NSObject, UICollectionViewDataSource { weak var parent: MyController? init(parent: MyController) { self.parent = parent super.init() } func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return parent?.items?.count ?? 0 } // 补全必须实现的cell生成方法 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DefaultCell", for: indexPath) // 你可以在这里根据items的内容给cell赋值 cell.contentView.backgroundColor = .systemGray5 return cell } }
内容的提问来源于stack exchange,提问作者sunset.
相关产品推荐
相关产品推荐

