I am making a custom collectionview cell Using XIB.
The collectionview is placed inside an viewController as an extension.
This is the code i am using to call the Xib View but i get an error telling me i need to use reuseidentifier. But i have no clue how to use that while using XIB.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell
return cell
}
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier - cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:'
*** First throw call stack:
First you need to create a reuseIdentifier for your cell. Lets create it based on your collectionViewCell class name. Declare reuseId, in your ViewController file:
let reuseId = String(describing: CustomCell.self)
You need to register your cell to your collectionView in viewDidLoad method.
collectionView.register(CustomCell.self, forCellReuseIdentifier: reuseId)
Then in your cellForItemAt method:
guard let cell = collectionView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath) as? CustomCell else { return UICollectionViewCell() }
//return cell, or update cell elements first.
You can register the CustomCell like,
let customCellNib = UINib(nibName: "CustomCell", bundle: .main)
collectionView.register(customCellNib, forCellWithReuseIdentifier: "CustomCell")
And use the same registered cell in cellForItemAt like,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier:"CustomCell", for: indexPath) as? CustomCell else {
return UICollectionViewCell()
}
return cell
}
For Swift 4.0 and 4.2
In your viewDidLoad:
custom collectionViewCell
mainCollectionView.register(UINib(nibName: "your_custom_cell_name", bundle: nil), forCellWithReuseIdentifier: "your_custom_cell_identifier")
In cellForItemAt indexPath:
let cell : <your_custom_cell_name> = mainCollectionView.dequeueReusableCell(withReuseIdentifier: "your_custom_cell_identifier", for: indexPath) as! <your_custom_cell_name>
And don't forget to set identifier for your custom cell in xib section.
Related
I have a UICollectionView that I want to make 3 custom cells appear.
I have read the documentation but I haven't been able to fix this issue.
Is there something I am missing?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
I have tried changing the return 1 to 3 to make 3 custom cells appear but it only makes the 1st custom cell appear 3 times.
I have created a video and linked the video below explaining my situation.
https://www.loom.com/share/9b5802d6cc7b4f9a93c55b4cf7d435bb
Edit I have used #Asad Farooq method and it seems to have worked for me. I added my CollectionView's shown below and I can now make custom cells!
if(indexPath.item==0)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DailyCollectionViewCell", for: indexPath) as! DailyCollectionViewCell
return cell
}
if(indexPath.item==1)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WeeklyCollectionViewCell", for: indexPath) as! WeeklyCollectionViewCell
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MonthlyCollectionViewCell", for: indexPath) as! MonthlyCollectionViewCell
return cell
}
}
As we can see from the documentation of Apple,
You typically don’t create instances of this class yourself. Instead, you register your specific cell subclass (or a nib file containing a configured instance of your class) using a cell registration. When you want a new instance of your cell class, call the dequeueConfiguredReusableCell(using:for:item:) method of the collection view object to retrieve one.
We have to register the cell to the collectionView before using it, for example:
class CustomCollectionViewCell: UICollectionViewCell {
// my custom collection view cell
}
Then we gonna register it to the collection view:
class MyViewController: UIViewController {
...
override func viewDidLoad(){
super.viewDidLoad()
...
self.myCollectionView.dataSource = self
// register the cells, so the collectionView will "know" which cell you are referring to.
self.myCollectionView.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellReuseIdentifier: "customReuseIdentifier")
// register all type of cell you wanted to show.
}
}
extension MyViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return number of cell you wanted to show, based on your data model
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = routineCollectionView.dequeueReusableCell(withReuseIdentifier: "customReuseIdentifier", for: indexPath) as! CustomCollectionViewCell
// cast the cell as CustomCollectionViewCell to access any property you set inside the custom cell.
// dequeue cell by the reuseIdentifier, "explain" to the collectionView which cell you are talking about.
return cell
}
}
The above code snippet is just a brief example, but I hope that explain the idea.
If you got multiple type of custom cell, you'll have to create classes for them (sub-class of UICollectionViewCell), register them to your collectionView, and dequeue them in collectionView(cellForRowAt:).
There are plenty of tutorial on the internet, here share one of my favourite:
https://www.raywenderlich.com/9334-uicollectionview-tutorial-getting-started
Edit:
If you are using storyboard only to add your custom collectionViewCell, you don't need to register the cell again, the cell already existed in the collectionView (Sorry the above code is just my preference). Just set the class & identifier of the cell, and dequeue the cell using the identifier in collectionView(cellForRowAt:).
We have to register the three different custom cell to the collectionView before using it then inside this function add this code
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(indexPath.item==0)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! cell1
return cell1
}
if(indexPath.item==1)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! cell2
return cell2
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell3", for: indexPath) as! cell3
return cell3
}
This is driving me insane. I've put together dozens of collections views in the past, but this one is refusing to work.
I have a xib for my collection view cell, and I gave it an identifier, "My Cell". In my controller, I do the following:
override func awakeFromNib() {
super.awakeFromNib()
myCollectionView.delegate = self
myCollectionView.dataSource = self
// Register the collection view cell
myCollectionView.register(UINib(nibName: "MyCell", bundle: nil), forCellWithReuseIdentifier: "MyCell")
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath as IndexPath) as? MyCell else {
fatalError("The dequeued cell is not an instance of MyCell.")
}
return cell
}
Yet no matter what I do, Xcode is crashing and giving me this error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier MyCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
I've tried cleaning the build folder, restarting Xcode, even restarting my Mac, and nothing works.
What am I doing wrong??
Check if you are providing the same exact identifier. Copy/Paste to make sure they are the same.
I think you have to check two things
use this myCollectionView.dequeueReusableCell
`
override func awakeFromNib() {
super.awakeFromNib()
myCollectionView.delegate = self
myCollectionView.dataSource = self
// Register the collection view cell
myCollectionView.register(UINib(nibName: "MyCell", bundle: nil), forCellWithReuseIdentifier: "MyCell")
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = myCollectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath as IndexPath) as? MyCell else {
fatalError("The dequeued cell is not an instance of MyCell.")
}
return cell
}`
Open Xib file and check whether reusable identifier is set or not
Hope this will solve your issue , if not let me know
I wrote a custom component that uses UICollectionView and this UICollectionView has also custom UICollectionViewCell class with xib file.
In my UIViewController class viewDidLoad method, I send a web service request and after the response comes I register my custom UICollectionViewCell with this code;
let bundle = Bundle(for: MyCustomCellClass.self)
let nib = UINib(nibName: "MyCustomCellClass", bundle: bundle)
collectionView.register(nib, forCellWithReuseIdentifier: MyCustomCellClass.reuseIdentifier)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.reloadData()
Then in my UICollectionView cellForItemAt I dequeue cell with this way;
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCustomCellClass.reuseIdentifier, for: indexPath) as? MyCustomCellClass else {
fatalError("Cell should be registered")
}
let carObject = myList![indexPath.row])!
cell.carImageView.image = carObject.image
return cell
}
The problem exists after I scroll, the car image has gone. That is because my MyCustomCellClass image view outlet becomes suddenly nil.
I can't find the solution, any help would be greatly appreciated.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let row=animals[indexPath.row]
let cellIdentifier = "memoCell"
let cell=tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MemoCellTableViewCell
print(cell)
print("mmmmmmm")
print(cell.subject)
cell.name?.text="aaa"
return cell
}
I'm unable to set value to label, because I have an error saying:
'unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
So, I added tableView.register(MemoCellTableViewCell.self, forCellReuseIdentifier: "memoCell"). Then, the problem is that I can't set a value to cell.name because cell.name is nil.
First check that your outlet to the cell.name is connected perfectly then you can try by updating your method in below manner,
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let row=animals[indexPath.row]
let cellIdentifier = "memoCell"
var cell=tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MemoCellTableViewCell
if cell == nil {
cell = MemoCellTableViewCell(style: .default, reuseIdentifier: cellIdentifier)
}
print(cell)
print("mmmmmmm")
print(cell.subject)
cell.name?.text="aaa"
return cell
}
First of all remove this methods
tableView.register(MemoCellTableViewCell.self, forCellReuseIdentifier: "memoCell")
because your cell is in storyboard so you don't require this method, if you are using tableviewCell XIB then you can use this.
And in your MemoCellTableViewCell.swift file, create or connect all require outlet using storyboard and then try again. It should resolve issue, otherwise let me know.
I used UICollectionView to display my data, and I used a custom cell, in cellForItemAt fun App crashed when I want to assign value to label.
let reuseIdentifier = "brandCell"
ViewDidLoad------>
self.brandCollectionView!.register(BrandCercaCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
brandCollectionView.dataSource = self
brandCollectionView.delegate = self
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! BrandCercaCollectionViewCell
//App crashed here --->
cell.brandNameLabel.backgroundColor = UIColor.blue
return cell
}
I attached photos for storyBoard.
Thanks.
Make sure you set the identifier of your cell "brandCell" in the storyboard as the identifier for the collection view cell.