Reputation: 21
Trying to reload my tableView after a fetch request, however, it does not work. I have tableView with embedded collectionView in the first tableViewCell. Here is how my collectionView class looks like:
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()
}
when I chose didSelectItemAt, the delegate works and a function with a new API call executes in the UITableViewController, however, even though the API call is successful, the tableView cells remain the same, even after self.tableView.reloadData() is called. Here is how my UITableViewController class looks:
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()
}
}
}
}
}
Could anybody tell me what am I doing wrong here? Thank you in advance!
Upvotes: 0
Views: 1615
Reputation: 285160
Creating new instances of RegionsAndCountriesTableVC
in the table view cell which are not related to the parent view controller is not what you want and the reason of the issue.
You need the actual reference to the parent controller.
This can be accomplished pretty simply with a callback closure.
In RegionCell
define a callback property, it passes the region name
class RegionCell: UITableViewCell{
var callback : ((String) -> Void)?
...
and call it instead of the delegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let regionName = regions[indexPath.item].regionName.lowercased()
callback?(regionName)
}
Delete the entire code related to protocol/delegate.
In RegionsAndCountriesTableVC
assign the callback in 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
}
}
Upvotes: 1