Collection view not displaying Cells

I am trying to learn Xcode using iOS 14 Programming for Beginners. I have just entered the code to add the images and titles on the explore screen and have checked the code with the code written by the author and it is correct. When the Explore screen opens in the simulator it should show the images with titles on the screen. All that I get is the header at the top! I have checked the connection for the IBOutlets and the have the dot in the circle, so they are connected. The code builds OK, so I am not sure what is wrong? How can I find what is causing this problem? I have not mastered debugging yet, would this help?

Here is the ExploreCell.swift

//  ExploreCellCollectionViewCell.swift
//  EatOut
//
//  Created by Tony Hudson on 02/06/2021.
//

import UIKit

class ExploreCell: UICollectionViewCell {

    @IBOutlet weak var lblName: UILabel!
    @IBOutlet weak var imgExplore: UIImageView!
}

Here is ExploreItem.swift

//  ExploreItem.swift
//  EatOut
//
//  Created by Tony Hudson on 02/06/2021.
//

import Foundation

struct  ExploreItem {
    var name: String
    var image: String
}

    extension ExploreItem {
        init(dict: [String:AnyObject]) {
            self.name = dict["name"] as! String
            self.image = dict["image"] as! String
        }

    }

Here is ExploreDataManager.swift

//  ExploreDataManager.swift
//  EatOut
//
//  Created by Tony Hudson on 02/06/2021.
//

import Foundation

class ExploreDataManager {
    fileprivate var items: [ExploreItem] = []

    func fetch() {
        for data in loadData() {
            items.append(ExploreItem(dict: data))
        }
    }

    fileprivate func loadData() -> [[String: AnyObject]] {
        guard let path = Bundle.main.path(forResource: "ExploreData", ofType: "plist"), let items = NSArray(contentsOfFile: path) else {
            return [[:]]
        }
        return items as! [[String: AnyObject]]
    }

    func numberOfItems() -> Int {
        items.count
    }

    func explore(at index:IndexPath) -> ExploreItem {
        items[index.item]
    }
}

I think that is as much information that I can give! Can someone point me in the right direction so that I can solve this problem?

Accepted Reply

Have working back through the code steps and found that I had missed several lines of code, so is now working! Thanks!

Replies

You don't show enough code. Could you show the code where you define the delegate and data source functions for the collectionView ?

How is the cell defined ? Directly in the collectionView or with a specific nib ?

Look at your code, I bet you will come in a few minutes after discovering a major flaw, as usual.

Add a Comment

When you reloadData in your code?

  • Don't understand your question!

Add a Comment

I believe this is the code that you said I didn't show? ExploreView Controller:

//  ExploreViewController.swift
//  EatOut
//
//  Created by Tony Hudson on 16/05/2021.
//

import UIKit

class ExploreViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView  {
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath)
        return headerView
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return manager.numberOfItems()
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "exploreCell", for: indexPath) as! ExploreCell
        let item = manager.explore(at: indexPath)
        cell.lblName.text = item.name
        cell.imgExplore.image = UIImage(named: item.image)
        return cell
    }
    
    @IBOutlet weak var collectionView: UICollectionView!
    let manager = ExploreDataManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        let manager = ExploreDataManager()
        manager.fetch()

        // Do any additional setup after loading the view.
    }

    @IBAction func unwindLocationCancel(segue: UIStoryboardSegue) {
    }
} 

```

One observation: the last IBAction, doesn't appear to be connected (no dot in the circle).

As far as I know the cell is defined in the ExploreCell.swift shown in. first post. 
The author is trying to teach the readers MVC so the model files are:
ExploreItem.swift
ExploreDataManager.swift
The View item is ExploreCell.swift
Unfortunately, as far as I can see the code is correct against the author version I downloaded from the book.
If its not a typo the only other thing is that I have missed one of the steps.
If you can help I would be grateful!
 






  • Can you show the content of ExploreData.plist? And are you sure you have added it to the target?

Add a Comment

Hi OOPer The plist file is definitely added to the project, as I had to Create a new group called Model and then a new file which was the ExploreDat.plist. It is definitely in the Project Navigator. I tried to add a file using the paperclip icon below but when I go the the folder where it is stored, it is gray'd out. That would not prove much as it is a collection of 31 items with 2 fields (name & Image).

  • Sorry, but in the Project Navigator does not mean added to the target. And I do not understand what gray'd out means. Have you checked your loadData() returns non-empty value?

Add a Comment

As part of the instructions in the book, in the ExploreDataManager.swift i test that the data works by changing the line:

items.append(ExploreItem(dict: data))

With:

print(data)

It should print the data in the debug area, but it does not? What could cause this to happen? Is this what meant when you said have I checked loadData()?

As a check I have tried to simulate the error in Playground. This was also suggested in the book. Swear that when I first tried it some time ago it worked! The Playground produces the table in LiveView but is empty. Here is the code:

import UIKit
import PlaygroundSupport

class TableViewExampleController: UIViewController, UITableViewDataSource {
    var tableView: UITableView?
    var names: [String] = ["Jane", "Akhil", "Divij"]
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.bounds = CGRect(x: 0, y: 0, width: 375, height: 667)
        createTableView()
}

    func createTableView() {
        self.tableView = UITableView(frame: CGRect(x: 0, y: 0, width:
         self.view.frame.width, height: self.view.frame.height))
        self.tableView?.dataSource = self
        self.tableView?.backgroundColor = .white
        self.tableView?.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        self.view.addSubview(self.tableView!)
}

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        names.count
}

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        let name = names[indexPath.row]
        cell.textLabel?.text? = name
        return cell
    }

}

PlaygroundPage.current.liveView = TableViewExampleController()

It seems strange that both the main project and Playground suffer from the same problem? Is there anything in the setup or preferences that would cause this? I don't want to reinstall Xcode as it would mean I would have to start from the beginning again. Can anyone suggest why this behaviour is occurring?

Replace

        cell.textLabel?.text? = name

by

        cell.textLabel!.text = name

And it works.

You can test for safety:

if cell.textLabel != nil {
        cell.textLabel!.text = name
}

Right! The Playground code now works and in the ExploreDataManager.swift with the print(data) statement it prints the data in the debug area. On checking my code with the code I downloaded I found that the instructions were ambigious and I had put a statement in the wrong place in the ExploreViewController.swift file. Viz. let Manager = ExploreDataManager() should have been after The first @IBOutlet statement. But alas I still get the explore screen without the image and title when I run the app. I don't know if this is relevant, when the app is run I get a warning Here is the screen shot:

Could this be the reason that the images and text are not being loaded?

Have working back through the code steps and found that I had missed several lines of code, so is now working! Thanks!