Swift tableView.reloadData() 不会在 Swift 中重新加载 table 视图
Swift tableView.reloadData() does not reload table view in Swift
试图在获取请求后重新加载我的 tableView,但是它不起作用。
我在第一个 tableViewCell 中有带有嵌入式 collectionView 的 tableView。
这是我的 collectionView class 的样子:
class RegionCell: UITableViewCell, FetchRegionsDelegate {
static let reuseId = "regionCellID"
var collectionView: UICollectionView!
var tableViewManager = RegionsAndCountriesTableVC()
var selectedRegion: String?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
configureCollectionView()
tableViewManager.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCollectionView() {
collectionView = UICollectionView(frame: contentView.bounds, collectionViewLayout: createThreeColumnFlowLayout(in: contentView))
contentView.addSubview(collectionView)
collectionView.fillSuperview()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = .systemBackground
collectionView.register(RegionCollectionViewCell.self, forCellWithReuseIdentifier: RegionCollectionViewCell.reuseId)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
6
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RegionCollectionViewCell.reuseId, for: indexPath) as! RegionCollectionViewCell
let region = regions[indexPath.item]
cell.imageView.image = region.regionImage
cell.textLabel.text = region.regionName
if indexPath.row == 0 {
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .left)
cell.isSelected = true
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
tableViewManager.fetchByRegions(regionName: (regions[indexPath.item].regionName).lowercased())
self.tableViewManager.tableView.reloadData()
}
当我选择 didSelectItemAt 时,委托工作并且带有新 API 调用的函数在 UITableViewController 中执行,但是,即使 API 调用成功,tableView 单元格保持不变,即使在调用 self.tableView.reloadData() 之后。这是我的 UITableViewController class 的样子:
protocol FetchRegionsDelegate {
var selectedRegion: String? { get set }
}
class RegionsAndCountriesTableVC: UITableViewController {
var countries = [Country]()
var delegate: FetchRegionsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CountryCell.self, forCellReuseIdentifier: CountryCell.reuseId)
tableView.register(RegionCell.self, forCellReuseIdentifier: RegionCell.reuseId)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchInitialData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
section == 0 ? 1 : countries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: RegionCell.reuseId, for: indexPath)
return cell as! RegionCell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: CountryCell.reuseId, for: indexPath) as! CountryCell
cell.textLabel?.text = countries[indexPath.row].name
return cell
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
section == 0 ? "Regions" : "Country"
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
indexPath.section == 0 ? 250 : 45
}
// MARK: - FetchRequest
func fetchInitialData() {
let url = "https://restcountries-v1.p.rapidapi.com/all/?rapidapi-key=APIKey"
fetchGenericJSONData(urlString: url) { (countries: [Country]? , error) in
guard let safeCountries = countries else { return }
self.countries = safeCountries
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
func fetchByRegions(regionName: String) {
if regionName == "all" {
countries.removeAll()
fetchInitialData()
} else {
countries.removeAll()
print(self.countries.count)
let url = "https://restcountries-v1.p.rapidapi.com/region/\(regionName)/?rapidapi-key=APIKey"
fetchGenericJSONData(urlString: url) { (countries: [Country]?, error) in
guard let safeCountriesByRegion = countries else { return }
self.countries = safeCountriesByRegion
print(self.countries.count)
print(self.countries)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
有人能告诉我我做错了什么吗?
提前致谢!
在与父视图控制器无关的 table 视图单元格中创建 RegionsAndCountriesTableVC
的新实例不是您想要的,也是问题的原因。
您需要对父控制器的实际引用。
这可以通过回调闭包非常简单地完成。
在RegionCell
中定义一个回调属性,它传递区域名称
class RegionCell: UITableViewCell{
var callback : ((String) -> Void)?
...
并调用它而不是委托
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let regionName = regions[indexPath.item].regionName.lowercased()
callback?(regionName)
}
删除与protocol/delegate相关的全部代码。
在RegionsAndCountriesTableVC
中分配回调在cellForRow
中
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: RegionCell.reuseId, for: indexPath) as! RegionCell
cell.callback = { regionName in
self.fetchByRegions(regionName: regionName)
tableView.reloadData()
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: CountryCell.reuseId, for: indexPath) as! CountryCell
cell.textLabel?.text = countries[indexPath.row].name
return cell
}
}
试图在获取请求后重新加载我的 tableView,但是它不起作用。 我在第一个 tableViewCell 中有带有嵌入式 collectionView 的 tableView。 这是我的 collectionView class 的样子:
class RegionCell: UITableViewCell, FetchRegionsDelegate {
static let reuseId = "regionCellID"
var collectionView: UICollectionView!
var tableViewManager = RegionsAndCountriesTableVC()
var selectedRegion: String?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
configureCollectionView()
tableViewManager.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCollectionView() {
collectionView = UICollectionView(frame: contentView.bounds, collectionViewLayout: createThreeColumnFlowLayout(in: contentView))
contentView.addSubview(collectionView)
collectionView.fillSuperview()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = .systemBackground
collectionView.register(RegionCollectionViewCell.self, forCellWithReuseIdentifier: RegionCollectionViewCell.reuseId)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
6
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RegionCollectionViewCell.reuseId, for: indexPath) as! RegionCollectionViewCell
let region = regions[indexPath.item]
cell.imageView.image = region.regionImage
cell.textLabel.text = region.regionName
if indexPath.row == 0 {
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .left)
cell.isSelected = true
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
tableViewManager.fetchByRegions(regionName: (regions[indexPath.item].regionName).lowercased())
self.tableViewManager.tableView.reloadData()
}
当我选择 didSelectItemAt 时,委托工作并且带有新 API 调用的函数在 UITableViewController 中执行,但是,即使 API 调用成功,tableView 单元格保持不变,即使在调用 self.tableView.reloadData() 之后。这是我的 UITableViewController class 的样子:
protocol FetchRegionsDelegate {
var selectedRegion: String? { get set }
}
class RegionsAndCountriesTableVC: UITableViewController {
var countries = [Country]()
var delegate: FetchRegionsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CountryCell.self, forCellReuseIdentifier: CountryCell.reuseId)
tableView.register(RegionCell.self, forCellReuseIdentifier: RegionCell.reuseId)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchInitialData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
section == 0 ? 1 : countries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: RegionCell.reuseId, for: indexPath)
return cell as! RegionCell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: CountryCell.reuseId, for: indexPath) as! CountryCell
cell.textLabel?.text = countries[indexPath.row].name
return cell
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
section == 0 ? "Regions" : "Country"
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
indexPath.section == 0 ? 250 : 45
}
// MARK: - FetchRequest
func fetchInitialData() {
let url = "https://restcountries-v1.p.rapidapi.com/all/?rapidapi-key=APIKey"
fetchGenericJSONData(urlString: url) { (countries: [Country]? , error) in
guard let safeCountries = countries else { return }
self.countries = safeCountries
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
func fetchByRegions(regionName: String) {
if regionName == "all" {
countries.removeAll()
fetchInitialData()
} else {
countries.removeAll()
print(self.countries.count)
let url = "https://restcountries-v1.p.rapidapi.com/region/\(regionName)/?rapidapi-key=APIKey"
fetchGenericJSONData(urlString: url) { (countries: [Country]?, error) in
guard let safeCountriesByRegion = countries else { return }
self.countries = safeCountriesByRegion
print(self.countries.count)
print(self.countries)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
有人能告诉我我做错了什么吗? 提前致谢!
在与父视图控制器无关的 table 视图单元格中创建 RegionsAndCountriesTableVC
的新实例不是您想要的,也是问题的原因。
您需要对父控制器的实际引用。
这可以通过回调闭包非常简单地完成。
在RegionCell
中定义一个回调属性,它传递区域名称
class RegionCell: UITableViewCell{
var callback : ((String) -> Void)?
...
并调用它而不是委托
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let regionName = regions[indexPath.item].regionName.lowercased()
callback?(regionName)
}
删除与protocol/delegate相关的全部代码。
在RegionsAndCountriesTableVC
中分配回调在cellForRow
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: RegionCell.reuseId, for: indexPath) as! RegionCell
cell.callback = { regionName in
self.fetchByRegions(regionName: regionName)
tableView.reloadData()
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: CountryCell.reuseId, for: indexPath) as! CountryCell
cell.textLabel?.text = countries[indexPath.row].name
return cell
}
}