[Edit] If additional information is needed, I will be happy to provide it.
I have a situation that I have thus far been unable to figure out. A Collection View embedded inside of a table view; I am using a data dictionary for the data, a total of 7 sections. The problem is that on reloading the data it isn't reading the data dictionary correctly and it's displaying images and section names that do not go together.
One note: If I limit the dictionary to say 4 sections it works just fine, it is only when it's more than that that I am having the problem.
here is a copy of the data dictionary:
var data1 = [quoteData(sectionType: "For You", quotes: ["Categories/General.png"
]),
quoteData(sectionType: "Free Today", quotes: ["Categories/Loneliness.png", "Categories/Setting Goals.png"
]),
quoteData(sectionType: "Hard Times", quotes: ["Categories/Death.png", "Categories/Loneliness.png"
]),
quoteData(sectionType: "Calm Down", quotes:["Categories/Appreciation.png", "Categories/Managing Anxiety.png"
]),
quoteData(sectionType: "Relationships", quotes:["Categories/Friendship.png"
]),
quoteData(sectionType: "Personal Growth", quotes: ["Categories/Confidence.png", "Categories/Courage.png"
]),
quoteData(sectionType: "Spiritual and Philosophy", quotes: ["Categories/Poetry.png"
]),
]
View Controller is as follows:
extension CategoriesViewController: UITableViewDelegate, UITableViewDataSource {
//MARK: - Methods
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func numberOfSections(in tableView: UITableView) -> Int {
return data1.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return data1[section].sectionType
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! CategoriesTableViewCell
cell.collectionView.tag = indexPath.section
guard let catCell = cell as? CategoriesTableViewCell else {
return cell
}
catCell.didSelectItemAction = { [weak self] String in
self!.existingCat = (self?.defaults.string(forKey: "DefaultQuotes"))!
self?.defaultCat = String
if self?.defaultCat != "" {
if self?.defaultCat != "General" {
self?.adAlert()
} else {
// update
self?.defaults.set(self?.defaultCat, forKey: "DefaultQuotes")
self?.navigationController?.popViewController(animated: true)
}
} else {
self?.navigationController?.popViewController(animated: true)
}
}
return cell
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
view.layer.borderWidth = 4
view.layer.borderColor = UIColor.white.cgColor
if section == 0 {
view.tintColor = .clear
} else {
// view.tintColor = .colorFromHex("a5d7fa")
view.tintColor = .colorFromHex("ffffff")
}
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor.black
header.textLabel?.font = UIFont.preferredFont(forTextStyle: .title3)
}
func adAlert() {
let showAlert = UIAlertController(title: "Unlock Quotes", message: nil, preferredStyle: .alert)
//let image = UIImage(named: "MIsc/PaintBrushColor")
showAlert.addAction(UIAlertAction(title: "Watch Video", style: .default, handler: { action in
// Show Ad & update
self.showAd()
if self.defaultCat == self.existingCat {
self.defaults.set(false, forKey: "resetIndex")
} else {
self.defaults.set(true, forKey: "resetIndex")
}
// update the Default quotes data area and Highlight box
self.defaults.set(String(self.defaultCat), forKey: "DefaultQuotes")
// pop view controller
self.navigationController?.popViewController(animated: true)
}))
showAlert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { action in
}))
self.present(showAlert, animated: true, completion: nil)
}
The TableViewCell code: class CategoriesTableViewCell: UITableViewCell {
// Outlets
@IBOutlet weak var collectionView: UICollectionView!
//Constants
let defaults = UserDefaults.standard
// Variables
var resetIndex: Bool = false
var myCat: String = ""
var didSelectItemAction: ((String) -> Void)?
//Methods
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.delegate = self
collectionView.dataSource = self
myCat = defaults.string(forKey: "DefaultQuotes")!
resetIndex = defaults.bool(forKey: "ResetIndex")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension CategoriesTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath)
let lblQuote = cell.viewWithTag(80) as? UILabel
let dougie = data1[collectionView.tag].quotes[indexPath.row]
// Get range 4 places from the start, and 6 from the end.
let r = dougie.index(dougie.startIndex, offsetBy: 11)..<dougie.index(dougie.endIndex, offsetBy: -4)
// Access the string by the range.
let subString = dougie[r]
myCat = String(subString)
didSelectItemAction?(myCat)
//collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data1[collectionView.tag].quotes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! CategoriesCollectionViewCell
let Defaults = UserDefaults.standard
let defQuote = Defaults.string(forKey: "DefaultQuotes")
cell.images.image = UIImage(named: data1[collectionView.tag].quotes[indexPath.row])
let myLbl = cell.viewWithTag(80) as? UILabel
let myIcon = cell.viewWithTag(83) as? UIImageView
myIcon?.image = UIImage(named: "bed.double.circle")
let padlock = cell.viewWithTag(81) as? UIImageView
let dougie = data1[collectionView.tag].quotes[indexPath.row]
// Get range 4 places from the start, and 6 from the end.
let r = dougie.index(dougie.startIndex, offsetBy: 11)..<dougie.index(dougie.endIndex, offsetBy: -4)
// Access the string by the range.
let substring = dougie[r]
myLbl?.text? = String(substring)
if myLbl?.text == defQuote {
// we are going to set the border
cell.images?.layer.borderWidth = 2.5
cell.images?.layer.borderColor = UIColor.red.cgColor
cell.images?.clipsToBounds = true
} else {
cell.images?.layer.borderWidth = 0.0
cell.images?.layer.borderColor = UIColor.clear.cgColor
cell.images?.clipsToBounds = false
}
print(data1[collectionView.tag].sectionType)
let doggie = getImg(Inb: String(substring))
if doggie == "" {
let strIcon = "CatIcons/" + String(substring) + ".png"
myIcon?.image = UIImage(named: strIcon)
} else {
myIcon?.image = UIImage(systemName: doggie)
}
if myLbl?.text == "General" || data1[collectionView.tag].sectionType == "Free Today" {
padlock?.isHidden = true
} else {
padlock?.isHidden = false
}
return cell
}
func getImg(Inb: String) -> String {
var retVal: String
switch Inb {
case "General":
retVal = "rainbow"
case "Hope":
retVal = "sunrise"
case "Sleep":
retVal = "bed.double.circle"
case "Mindfulness":
retVal = "brain.head.profile"
case "Enjoy the Moment":
retVal = "figure.2"
case "Calm":
retVal = "figure.yoga"
default:
retVal = ""
}
return retVal
}
}
One possible issue in your code arises from the management of cell reuse and data synchronization between the table view and the embedded collection views, synchronizing the collection view's data by correctly setting its with a tag and reloading the collection view data in the cellForRowAt
method of your table view data source
Something like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! CategoriesTableViewCell
/*
Set the collection view tag to match the section index;
the tag will later be used to ensure
the correct data is loaded for each collection view.
*/
cell.collectionView.tag = indexPath.section
cell.collectionView.reloadData()
// Continue your code
}
Then you can use the tags
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// Use collectionView.tag to access the correct section of your data model.
return data1[collectionView.tag].quotes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! CategoriesCollectionViewCell
// Configure the cell using data1[collectionView.tag] to get the correct data for this collection view
let quote = data1[collectionView.tag].quotes[indexPath.row]
// Your code continues here
}
This is far from the best solution, but should work.