[英]Not using reusable cell in UITableView with CollectionView in each cell
我有一个UITableView
,在其原型单元中有一个UICollectionView
。
MainViewController
是UITableView
委托,而MyTableViewCell
类是UICollectionView
委托。
在更新每个TableViewCell
内容时,我调用cell.reloadData()
来使单元格内的collectionView重新加载其内容。
当我使用可重复使用的单元格时,随着每个单元格的出现,它的最后一个单元格的内容消失了! 然后,它从URL加载正确的内容。
我最多将有5到10个UITableViewCells
。 因此,我决定不对UITableView
使用可重复使用的单元格。 我将tableView方法中的单元格创建行更改为此:
let cell = MyTableViewCell(style: .default, reuseIdentifier:nil)
然后我在此函数的MyTableViewCell类(它是UICollectionView的委托)中出现错误:
override func layoutSubviews() {
myCollectionView.dataSource = self
}
EXC_BAD_INSTRUCTION CODE(code=EXC_I386_INVOP, subcode=0x0)
fatal error: unexpectedly found nil while unwrapping an Optional value
MyTableViewCell.swift
import UIKit
import Kingfisher
import Alamofire
class MyTableViewCell: UITableViewCell, UICollectionViewDataSource {
struct const {
struct api_url {
static let category_index = "http://example.com/api/get_category_index/";
static let category_posts = "http://example.com/api/get_category_posts/?category_id=";
}
}
@IBOutlet weak var categoryCollectionView: UICollectionView!
var category : IKCategory?
var posts : [IKPost] = []
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
if category != nil {
self.updateData()
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func layoutSubviews() {
categoryCollectionView.dataSource = self
}
func updateData() {
if let id = category?.id! {
let url = const.api_url.category_posts + "\(id)"
Alamofire.request(url).responseObject { (response: DataResponse<IKPostResponse>) in
if let postResponse = response.result.value {
if let posts = postResponse.posts {
self.posts = posts
self.categoryCollectionView.reloadData()
}
}
}
}
}
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath as IndexPath) as! MyCollectionViewCell
let post = self.posts[indexPath.item]
cell.postThumb.kf.setImage(with: URL(string: post.thumbnail!))
cell.postTitle.text = post.title
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//You would get something like "model.count" here. It would depend on your data source
return self.posts.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
}
MainViewController.swift
import UIKit
import Alamofire
class MainViewController: UITableViewController {
struct const {
struct api_url {
static let category_index = "http://example.com/api/get_category_index/";
static let category_posts = "http://example.com/api/get_category_posts/?category_id=";
}
}
var categories : [IKCategory] = []
override func viewDidLoad() {
super.viewDidLoad()
self.updateData()
}
func updateData() {
Alamofire.request(const.api_url.category_index).responseObject { (response: DataResponse<IKCategoryResponse>) in
if let categoryResponse = response.result.value {
if let categories = categoryResponse.categories {
self.categories = categories
self.tableView.reloadData()
}
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return self.categories.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.categories[section].title
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionHolderTableViewCell") as! MyTableViewCell
let cell = MyTableViewCell(style: .default, reuseIdentifier:nil)
cell.category = self.categories[indexPath.section]
cell.updateData()
return cell
}
}
MyCollectionViewCell.swift
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var postThumb: UIImageView!
@IBOutlet weak var postTitle: UILabel!
var category : IKCategory?
}
为什么不重用细胞导致此? 我为什么做错了?
有几件事可以帮助您快速入门。
首先,取消注释使用可重用单元格的行,并删除创建不可重用单元格的代码行。 在这里使用可重复使用的单元格是安全的。
其次,在MyTableViewCell
,在super.awakeFromNib()
调用之后MyTableViewCell
设置集合视图的dataSource
。 您只需要设置一次dataSource
,但是layoutSubviews()
可能会多次调用。 这不是根据需要设置dataSource的正确位置。
override func awakeFromNib() {
super.awakeFromNib()
categoryCollectionView.dataSource = self
}
我已经从awakeFromNib()
删除了对updateData()
的调用,因为您已经在创建单元格时对其进行了调用。 您也可以删除layoutSubviews()
覆盖,但是作为一般规则,覆盖它时应小心调用super.layoutSubviews()
。
最后,帖子似乎重新出现在错误的单元格中的原因是,在重复使用单元格时,并没有清空posts数组。 要解决此问题,请将以下方法添加到MyTableViewCell
:
func resetCollectionView {
guard !posts.isEmpty else { return }
posts = []
categoryCollectionView.reloadData()
}
此方法清空数组并重新加载您的集合视图。 由于阵列中现在没有帖子,因此集合视图将为空,直到您再次调用updateData为止。 最后一步是在单元格的prepareForReuse
方法中调用该函数。 将以下内容添加到MyTableViewCell:
override func prepareForReuse() {
super.prepareForReuse()
resetCollectionView()
}
让我知道事情的后续!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.