How to push data from nested array to collectionVIew in tableVIewCell - ios

My layout consists out of collectionviews with posters and those collectionviews are in tableviewcells
I load my data from the internet to Array>. The first array is for the tableviewcell, the second one is for the collectionview and then there's the struct with the URL to the poster. I always get error out of index.
I'm a newbie in iOS developing so any help would be appreciated!
Here's my code:
struct TVShowTitle {
var id: Int
var posterPath: String
}
class ForYouViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var tvShowIds: Array<Array<TVShowTitle>> = [[TVShowTitle]]()
var section = 0
var sectionNames = ["Comedy Blockbusters", "Exciting TV", "Horror", "Popular shows", "Sci-fi", "TV Dramas", "Thrillers"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sectionNames.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SectionCell", for: indexPath) as! SectionTableViewCell
section = indexPath.row
cell.sectionNameLabel.text = sectionNames[indexPath.row]
cell.imageCollectionView.reloadData()
return cell;
}
override func viewDidLoad() {
super.viewDidLoad()
getTitlesForMostOfTheSections()
}
func getTitlesForMostOfTheSections() {
// The function loads the URLs for the posters
self.tableView.reloadData()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ForYouViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! ImageCollectionViewCell
if tvShowIds.count <= section && indexPath.row <= tvShowIds[section].count {
cell.imageView.sd_setImage(with: URL(string: "https://image.tmdb.org/t/p/w300" + tvShowIds[section][indexPath.row].posterPath))
} else {
cell.imageView.image = #imageLiteral(resourceName: "placeholder")
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1;
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// How many shows in a section
if section > tvShowIds.count || tvShowIds.count == 0 {
return 0
} else {
return tvShowIds[section].count
}
}
}

Related

Nested UICollectionView returning the same values for each section - Swift

I have a UICollectionView nested inside of a UITableViewCell. The collectionview inside of each tableviewcell section should return different data according to the section. Here is my code:
ViewController.swift
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var categoryKeys: [String]?
let network = MediaNetworking()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// fetch data
network.fetchMedia()
tableView.delegate = self
tableView.dataSource = self
print("hello world")
}
func numberOfSections(in tableView: UITableView) -> Int {
self.categoryKeys = network.categoryKeys
return self.categoryKeys!.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SectionTableViewCell
cell.theArray = network.sharedArray
cell.accessArray = network.accessArray
cell.backgroundColor = .purple
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
self.categoryKeys = network.categoryKeys
return self.categoryKeys?[section]
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 300
}
}
SectionTableViewCell.swift
class SectionTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var categoryKeys: [String]?
var theArray: [String: [Entity]]?
var accessArray: [Entity]?
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.delegate = self
collectionView.dataSource = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return accessArray!.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MediaCollectionViewCell
cell.artistLabel.text = accessArray![indexPath.row].name
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionHeaderView", for: indexPath) as! SectionHeaderView
if indexPath.section < categoryKeys!.count {
let category = categoryKeys![indexPath.section]
sectionHeader.categoryLabel.text = category
}
return sectionHeader
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 400, height: 300)
}
}
Right now all the collectionview cells are returning the same values. Any ideas on what I might be missing?..
Did you try to call collectionView.reloadData() after changing the data arrays?
cell.theArray = network.sharedArray
cell.accessArray = network.accessArray
cell. collectionView.reloadData()

Segue in a UICollectionView embedded in a UITableviewCell, Swift

I have made a UICollectionView inside a UITableViewCell and it works pretty Fine. My only Problem is, that I can't perform a Segue on didSelectItemAt Method to another ViewController.
I know I have to perform it from the TableViewController,I made a segue on the Storyboard and I tried multiple possibilities but for some reasons it doesn't work.
Here my TableviewController:
import UIKit
import RealmSwift
import SwiftyJSON
class HomeVTwoTableViewController: UITableViewController {
let realm = try! Realm()
let headers = ["1","2","3"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
self.tableView.separatorStyle = .none
}
//MARK: Custom Tableview Headers
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return headers[section]
}
//MARK: DataSource Methods
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
//Choosing the responsible PrototypCell for the Sections
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
cell.update()
return cell
} else {
return UITableViewCell()
}
}
// This on of my tries to perform a segue
func liveCellSelected() {
performSegue(withIdentifier: "showChat", sender: nil)
}
}
And here my TableViewCell with the embedded CollectionView:
import UIKit
import RealmSwift
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension HomeVTwoTableViewCell:
UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return(liveCommunities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//removes the old image
cell.imageView.image = UIImage(named: "No Image")
cell.titleLbl.text = nil
//set url and Picture
url = (liveCommunities?[indexPath.row].pictureId)!
let name : String = (liveCommunities?[indexPath.row].communityName)!
let channelName : String = (liveCommunities?[indexPath.row].channelName)!
cell.titleLbl.text = name
cell.senderLbl.text = channelName
cell.imageView.downloadedFrom(link :"someSecretUrl")
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
HomeVTwoTableViewController().liveCellSelected()
}
}
I found another question with a similar theme, but couldn't implement a delegate Protocol without creating problems with the already existing delegates.
Maybe it`s an obvious mistake but I can't see it.
Thanks in advance.
You're instantiating a new instacne of your home controller with this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
HomeVTwoTableViewController().liveCellSelected()
}
what you should do is to make it via a delegate, or you move your collectionview delegate to the main controller
protocol CellCollectionViewDelegate: class{
func didselect()
}
and you implement the delegate in cell and your home controller
May be you can create a variable to handle this. You can do optional also.
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
#IBOutlet weak var collectionView: UICollectionView!
var didSelectAction: () -> Void // add your action here
Here you can call to this function
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
HomeVTwoTableViewController().liveCellSelected()
didSelectAction() // Invoque your action
}
//On the cell creator, add the navigation or logic when you want to tap the cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
cell.update()
cell.didSelectAction = {
// add here your navigation
}
return cell
} else {
return UITableViewCell()
}
}
Ok as it seems there are two Solutions to this Problem.
One is via a Variable and one via a delegate. As I know the delegate one is more common.
Solution 1 with Variable:
Here my TableviewController:
import UIKit
class TableViewController: UITableViewController {
let headers = ["1","2","3"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
//Fill function, insert Navigation
cell.didSelectAction = {
self.performSegue(withIdentifier: "testSegue", sender: nil)
}
return cell
}
And here my TableViewCell with the embedded CollectionView:
import UIKit
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
//Instantiate function
var didSelectAction: () -> Void = {}
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension HomeVTwoTableViewCell:
UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return(liveCommunities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//removes the old text
cell.titleLbl.text = nil
cell.senderLbl.text = nil
let name : String = (liveCommunities?[indexPath.row].communityName)!
let channelName : String = (liveCommunities?[indexPath.row].channelName)!
cell.titleLbl.text = name
cell.senderLbl.text = channelName
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
// Invoque your action
didSelectAction()
}
}
Solution 2 with Delegate and Protocol:
Here my TableviewController:
import UIKit
class TableViewController: UITableViewController {
let headers = ["1","2","3"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
//Add delegate
cell.delegate = self
return cell
}
//Add Extension with Navigation
extension HomeVTwoTableViewController: CellCollectionViewDelegate {
func didSelect() {
performSegue(withIdentifier: "showChat", sender: nil)
}
}
And here my TableViewCell with the embedded CollectionView:
import UIKit
//Create a delegate protocol
protocol CellCollectionViewDelegate: class{
func didSelect()
}
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
//Add a delegate property
weak var delegate: CellCollectionViewDelegate?
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
}
//Adopt and implement the Delegate Protocol
extension HomeVTwoTableViewCell:
UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return(liveCommunities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//removes the old text
cell.titleLbl.text = nil
cell.senderLbl.text = nil
let name : String = (liveCommunities?[indexPath.row].communityName)!
let channelName : String = (liveCommunities?[indexPath.row].channelName)!
cell.titleLbl.text = name
cell.senderLbl.text = channelName
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
//call delegate method
delegate?.didSelect()
}
}
I tried to sum up the Solutions from
Abdoelrhman Mohamed and Alexkater and write it out in detail.
Tell me if something is wrong or left out.

Getting the TableView Section Title from TableViewCell, swift

I have a TableView with two kind of Cells, both are filled with a CollectionView. In the TableViewController I let them them display with a simple if Statement.
My TableViewController:
import UIKit
import RealmSwift
import Alamofire
import SwiftyJSON
let myGroupLive = DispatchGroup()
let myGroupCommunity = DispatchGroup()
class HomeVTwoTableViewController: UITableViewController {
var headers = ["Live", "Channel1", "ChannelTwo", "Channel3", "Channel4", "Channel5", "Channel6"]
override func viewDidLoad() {
super.viewDidLoad()
DataController().fetchSomeDate(mode: "get")
DataController().fetchSomeOtherData(mode: "get")
}
//MARK: Custom Tableview Headers
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return headers[section]
}
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
view.tintColor = UIColor.black
let header = view as! UITableViewHeaderFooterView
if section == 0 {
header.textLabel?.textColor = UIColor.black
view.tintColor = UIColor.white
}
else {
view.tintColor = UIColor.groupTableViewBackground
}
}
//MARK: DataSource Methods
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
//Choosing the responsible PrototypCell for the Sections
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
}
//Set custom cell height, has to match the CollectionView height
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 225.0
}
else {
return 120.0
}
}
}
My TableViewCellSmall:
import UIKit
import RealmSwift
var communities: Results<Community>?
class HomeVTwoTableViewCellSmall: UITableViewCell{
#IBOutlet weak var collectionView: UICollectionView!
}
extension HomeVTwoTableViewCellSmall: UICollectionViewDataSource,UICollectionViewDelegate {
//MARK: Datasource Methods
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return (communities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellSmall", for: indexPath) as? HomeVTwoCollectionViewCellSmall else
{
fatalError("Cell has wrong type")
}
//Here I want my Sorting Statement to make unique content per collection view
//normal approach if no section is asked
let url : String = (communities?[indexPath.row].pictureUri)!
let name :String = (communities?[indexPath.row].communityName)!
cell.titleLbl.text = name
cell.imageView.downloadedFrom(link :"somelink")
return cell
}
//MARK: Delegate Methods
override func layoutSubviews() {
myGroupCommunity.notify(queue: DispatchQueue.main, execute: {
let realm = try! Realm()
communities = realm.objects(Community.self)
self.collectionView.dataSource = self
self.collectionView.delegate = self
})
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
do something
}
}
My Problem is now, I want the "Channel Cells" to fill with customized and different data, in the CollectionView. That means I need some sort of key to get the right data in the right cell. My approach would be to take the SectionHeader Title, but for some reasons I cant access it from the TableViewCellSmall. So I have all the data in all the Cells and cant sort them without my Key.
Thanks in Advance.
from what I understand you need to fill the collectionview of each cell with different contents and for this needs to identify the cell?
If so, I used the method below that helped me, you can try.
If in doubt let me know so I can help, I hope I have helped :)
//TableViewCell Add
var didCollectionViewCellSelect: ((Int) -> Void)?
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//TabelView Add
class myClass: UITableViewController
{
var storedOffsets = [Int: CGFloat]()
override func viewDidLoad()
{
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
guard let tableViewCell = cell as? myTableViewCell else { return }
let secao = indexPath.section*1000 //Section
let linha = indexPath.row //Row
let posicao = secao+linha
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: posicao)
tableViewCell.collectionViewOffset = storedOffsets[posicao] ?? 0
}
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
guard let tableViewCell = cell as? myTableViewCell else { return }
let secao = indexPath.section*1000 //Section
let linha = indexPath.row //Row
let posicao = secao+linha
storedOffsets[posicao] = tableViewCell.collectionViewOffset
}
}
//CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
let posicao = collectionView.tag
let secao = Int(collectionView.tag/1000) //Section
let linha = posicao-(secao*1000) //Row
var qtd = 0
if secao == 0 && arrStation.count > 0
{
qtd = arrStation.count
}
return qtd
}

Collectionview in a TableView - How to select item?

I have made a CollectionView in a TableView for vertical and horizontal scrolling and customisable cells. This works so far. The problem is: I can't select an item of the CollectionView. I think the problem could be something with the delegate outlets but I could't find a solution.
I'm pretty new with Swift, so maybe I overlook something obvious.
My TableViewController:
import UIKit
class HomeVTwoTableViewController: UITableViewController {
var headers = ["Live", "Friends", "Last commented"]
#IBAction func cancelBtnPressed(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return headers[section]
}
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
view.tintColor = UIColor.black
let header = view as! UITableViewHeaderFooterView
if section == 0 {
header.textLabel?.textColor = UIColor.black
view.tintColor = UIColor.white
}
else {
view.tintColor = UIColor.groupTableViewBackground
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 225.0
}
else {
return 120.0
}
}
}
My TableViewCell with the CollectionView:
import UIKit
class HomeVTwoTableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
fileprivate var images = [UIImage]()
{
didSet
{
self.collectionView.reloadData()
}
}
func setup(for images: [UIImage])
{
self.images = images
}
override func layoutSubviews() {
collectionView.dataSource = self
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return communityName.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return communityName.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelect")
selectedCommunity = communityId[indexPath.row]
let home = HomeViewController()
home.showCommunityDetail()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//cell.imageView.image = image
cell.titleLbl.text = communityName[indexPath.row]
cell.imageView.downloadedFrom(link :"deleted because privat")
return cell
}
}
My CollectionViewCell:
import UIKit
class HomeVTwoCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLbl: UILabel!
}
You need to set delegate and dataSource like this
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.dataSource = self
collectionView.delegate = self
}
I think you missed this line. Just add, it will work fine collectionView.delegate = self
You have not confirm delegate of collection view.
override func layoutSubviews() {
collectionView.dataSource = self
collectionView.delegate = self
}

what do I set as the Datasource and delegate for a collectionView within a table

I have a View Controller that contains a table and a collection view in the prototype cell. I have set the VC as the both the DataSource and Delegate for the Table but my question is what do I set as the Datasource and delegate of the collectionView
My code works fine when I simply hardcode the number of sections etc for the collection view. However when I try read an array from a plist file something goes wrong and the same images are displayed for each section
enter image description here
Here is the code for the tableViewCell
import UIKit
class CategoryRow: UITableViewCell {
var pictDataSource = PicDataSource()
}
// Mark: Set-up the CollectionView
extension CategoryRow: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return pictDataSource.numberOfSections
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pictDataSource.numberOfPicsInSection(section)
// return 12
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "videoCell", for: indexPath) as! CategoryRowCollectionViewCell
if let picc = pictDataSource.picForItemAtIndexPath(indexPath) {
cell.pic = picc
}
configreCell(cell, atIndexPath: indexPath)
return cell
}
func configreCell(_ cell: CategoryRowCollectionViewCell, atIndexPath indexPath: IndexPath) {
cell.cellLabel.text = "\(indexPath.row)"
}
}
// Mark: Create the CollectionView flow layout
extension CategoryRow: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemsPerRow: CGFloat = 4
let hardCodedPadding: CGFloat = 5
let itemWidth = (collectionView.bounds.width/itemsPerRow) - hardCodedPadding
let itemHeight = collectionView.bounds.height - (2 * hardCodedPadding)
return CGSize(width: itemWidth, height: itemHeight)
}
}
And this is the code to read from dataSource
//
// PicDataSource.swift
import Foundation
import UIKit
class Pict {
var caption: String
var imageName: String
var section: String
var index: Int
init(caption: String, imageName: String, section: String, index: Int) {
self.caption = caption
self.imageName = imageName
self.section = section
self.index = index
}
convenience init(copying pic: Pict) {
self.init(caption: pic.caption, imageName: pic.imageName, section: pic.section, index: pic.index)
}
}
class PicDataSource {
var pics: [Pict] = []
var sections: [String] = []
var immutablePics: [Pict] = []
var count: Int {
return pics.count
}
var numberOfSections: Int {
return sections.count
}
init() {
pics = loadImagesFromDisk()
immutablePics = pics
}
func loadImagesFromDisk() -> [Pict] {
sections.removeAll(keepingCapacity: false)
if let path = Bundle.main.path(forResource: "Images", ofType: "plist") {
if let dictArray = NSArray(contentsOfFile: path) {
// print ("DICTARRAY COUNT", dictArray.count)
var pics: [Pict] = []
for item in dictArray {
if let dict = item as? NSDictionary {
let caption = dict["caption"] as! String
let imageName = dict["imageName"] as! String
let section = dict["section"] as! String
let index = dict["index"] as! Int
let pic = Pict(caption: caption, imageName: imageName, section: section, index: index)
if !sections.contains(section) {
sections.append(section)
}
pics.append(pic)
}
}
return pics.sorted { $0.section < $1.section }
}
}
return []
}
func numberOfPicsInSection(_ index: Int) -> Int {
let pics = picsForSection(index)
return pics.count
}
func picForItemAtIndexPath(_ indexPath: IndexPath) -> Pict? {
if indexPath.section > 0 {
let picss = picsForSection(indexPath.section)
return picss[indexPath.item]
} else {
return pics[indexPath.item]
}
}
func titleForSectionAtIndexPath(_ indexPath: IndexPath) -> String? {
if indexPath.section < sections.count {
return sections[indexPath.section]
}
return nil
}
func picsForSection(_ index: Int) -> [Pict] {
let section = sections[index]
let picsInSection = pics.filter { (pic: Pict) -> Bool in
return pic.section == section
}
return picsInSection
}
}
The ViewController
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
// var categories = ["Action", "Drama", "Science Fiction", "Kids", "Horror"]
var categories = PicDataSource()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return categories.numberOfSections
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories.sections[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CategoryRow
return cell
}
}
If anyone has any ideas or pointers as to what I'm doing wrong I be gratefull
You set the collection view's dataSource and delegate to whatever class will be implementing the UICollectionViewDataSource and UICollectionViewDelegate methods. It's likely this will be the same view controller used as your table view's dataSource and delegate but it doesn't have to be.

Resources