Taking first plunge with collection views and am running into this error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
The code is very simple, as shown below. I can't for the life of me figure out what it is that I'm missing.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
The collection view controller was created using a nib and the delegates & datasources are both set to file's owner.
View Controller's header file is also really basic.
#interface NewMobialViewController_3 : UICollectionViewController <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
#end
From the UICollectionView documentation for the dequeue method:
Important: You must register a class or nib file using the registerClass:forCellWithReuseIdentifier: or registerNib:forCellWithReuseIdentifier: method before calling this method.
You need to use same identifier between the dequeueReusableCellWithReuseIdentifier's argument and the UICollectionViewCell's property.
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CollectionViewCell" forIndexPath:indexPath];
Complementing what #jrtuton written... What you need is:
1) Register your nib file to "connect" it with your identifier:
//MyCollectionView.m
- (void) awakeFromNib{
[self registerNib:[UINib nibWithNibName:#"NibFileName" bundle:nil] forCellWithReuseIdentifier: #"MyCellIdentifier"];
}
2) Use your identifier to load your custom cell from a nib:
//MyCollectionView.m
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCollectionViewCell* cell = [cv dequeueReusableCellWithReuseIdentifier:#"MyCellIdentifier" forIndexPath:indexPath];
}
3) Use always static NSString* to avoid the same identifiers again in your app.
Swift 5
1) Make sure you have a correct deque for HEADER, you might be using the regular for normal cells.
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerId, for: indexPath)
return header
}
2) doubleCheck the registration (ViewDidLoad)
collectionView.register(HeaderCell.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerId)
i had everything 100% done correctly.
but for some reason i got the same error for an hour, then what i did is:
go to storyboard
select the prototype cell (in my case)
clear the class name from identity inspector, then rewrite it
rewrite the identifier name in the attributes inspector
simply, redid this step even tho i made it correct before, its like xcode misses something at a specific nanosecond!
Swift4.0
Whenever your UITableViewCell is xib at that time you must have to register with UITableView.
override func viewDidLoad(){
super.viewDidLoad()
self.yourtableview.register(UINib(nibName: "yourCellXIBname", bundle: Bundle.main), forCellReuseIdentifier: "YourCellReUseIdentifier")
}
Please be sure to check the ViewController Custom Class correct if the project is having multiple ViewControllers. And then make sure whatever the "collectionView.dequeueReusableCell(withReuseIdentifier: "ABC", for: indexPath) as?" matches with the identifier used in Collection Reusable View inside the Collection View.
If you are using storyboard instead of xib, here are few steps.
Making sure you fill the right identifier of your cell.
In the ColletionViewDelegate.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCellName", for: indexPath)as! YourCellName
return cell
}
That's it. You also don't want to add registerClass:forCellWithReuseIdentifier: which will cause element nil error.
You need to give correct reuseble identifier in storyboard, which you have give in the code while registering the collectionViewCell.
Here is the code.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ClctnVC", for: indexPath)as! ClctnVC
return cell
}
What fixed this for me was (roughly) same as Omar's answer, except I ended up creating a new UICollectionViewCell custom class and giving the Cell Reuse Indentifier a new / different name than the one that I had used elsewhere in the application. It worked immediately after that.
Just in case, if you are working with storyboard set collectionView identifier in the right place in the Attributes Inspector -> Identifier field. Not under the class name in "Restoration ID".
If you are using collection view in tableView cell, add delegates to tableView cell not in the tableViewController.
I had the same problem.
When I created a CollectionViewController, the default reuseIdentifier was Cell with capital C, but I made a mistake and made my cell identifier in Storyboard to be cell
They must be the same.
If you ever try solution in answer another in issue not work but in code is correct syntax ,correct outlet UI.
You should check in you tableview or collectionview then check you maybe forget set delegate "tableview.delegate = self or collectionview.delegate = self"
collectionview.delegate = self
collectionview.dataSource = self
In my case is only you design collection overlap collection in your cell.
thank you.
I know this is an old one, but I've experienced the same problem and wanted to share what fixed it for me.
In my case, I've declared a global identifier
let identifier = "CollectionViewCell"
and had to use self right before using it:
collectionView.dequeueReusableCellWithReuseIdentifier(self.identifier, forIndexPath: indexPath) as! CollectionViewCell
Hope this helps someone :)
If you create it by code, you must create a custom UICollectionViewCell, Then, init a UICollectionView ,and use loadView to set the view is the UICollectionView that you create. If you create in viewDidload() , it does not work. In addition, you can also drag a UICollectionViewController, it saves a lot of time.
Related
Long story short. I have a ViewController that has a ColletionView that's the main component of the page. The CollectionView has 2 reusable cell a Header and a Footer. I would like to have a TableView inside the footer but that's not possible I get the following error when I try to connect the TableView:
"Illegal Configuration: The tableView outlet from the ViewController to the UITableView is invalid. Outlets cannot be connected to repeating content."
My tip is that I want to achieve this in a total wrong way.
I want to achieve the following:
[SOLVED]
The solution was the following: I made a CollectionReusableView file for the Footer then exactly when #karem_gohar said I passed the following:
footer.tableView.delegate = footer.self
footer.tableView.dataSource = footer.self
I connected the tableView to the CollectionReusableView, I made an array to test it out I filled the tableView with the elements of the array.
Ps.:I made a TableViewCell and linked a label to it. The label showed the element of the array.
I assume you did register the footer/header nib like this:
segmentCollectionView.register(UINib(nibName: /* CellNibName */, bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: /* CellId */)
and then dequeue the cell like this
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionFooter {
let cell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: /* CellId */, for: indexPath) as! /* Your Class */
}
else {
}
}
so the trick is in your registered cell class as a footer you can go to the xib file and add the UITableView inside the reference /* Your Class */
link the UITableView in the cell class not theUIViewControllerclass that contains theUICollectionView`
then pass the data you want when you dequeue the cell and perform all your business inside the cell class
I'm loading a collectionview in my storyboard. But when I run it, it was not showing up. It was then that I figured out that the delegate and datasource was not set. But when I set the delegate & datasource and run again, the program crashes saying 'could not dequeue a view of kind: UICollectionElementKindCell with identifier prdImgscellIdentifier - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
It seems I didn't miss anything..but not able to figure out why the crash is happening..
This is my cellForItemAt...
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! productImagesCollectionViewCell
cell.myImageView.image = UIImage(named: "appLogo.jpg")
return cell
}
Set cell identifier in CollectionViewCell in Storyboard as prdImgscellIdentifier,
Or may be if it is because you haven't registered your xib to UICollectionView. If you are using UICollectionViewCell from Xib, you must register it first.
In viewDidLoad:
write it:
collectionView.register(UINib(nibName: "name", bundle: nil), forCellWithReuseIdentifier: "cellIdentifier")
You may need to register your customCellClass in viewDidLoad... Please check this previous answer for full details:
Swift - could not dequeue a view of kind: UICollectionElementKindCell with identifier
have u implemented required datasource?
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
Select your storyboard on storyboard and assign an Identifier in utilities window "cell" like Below in this image
I'm working with an UICollectionView. As dequeueReusableCell(withReuseIdentifier:for:) expects You must register a class or nib file using the register(_:forCellWithReuseIdentifier:) method before calling this method, I added a line in my viewDidLoad func as
self.collectionView!.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
Now when I'm using the cell for dequeuing and configuring, I'm getting error and app crashes.
fatal error: unexpectedly found nil while unwrapping an Optional value
This is my DataSource method:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
for: indexPath) as! PhotoCollectionViewCell
let aPhoto = photoForIndexPath(indexPath: indexPath)
cell.backgroundColor = UIColor.white
cell.imageView.image = aPhoto.thumbnail //this is the line causing error
return cell
}
And this is my PhotoCollectionViewCell class
class PhotoCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView! //I double checked this IBOutlet whether it connects with Storyboard or not
}
Original question
Now comes the interesting part.
I'm using a prototype cell in the UICollectionView and I set a reusable identifier from attributes inspector. Also I changed the custom class from identity inspector to my PhotoCollectionViewCell.
I searched for the same issue and found out that when using prototype cell, deleting
self.collectionView!.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
from code will work. I gave it a try and it works.
But I'm curious to know the reason behind this issue. I couldn't reproduce the same issue with UITableView but with UICollectionView.
Not a possible duplicate:
This UICollectionView's cell registerClass in Swift is about how to register class in UICollectionView. But my question doesn't expect how to register. My question is about an issue that isn't true with UITableView class but with UICollectionView only. I'm expecting the actual difference between this conflicting issue.
There are 3 ways to register a cell (either for UITableView or UICollectionView).
You can register a class. That means the cell has no nib or storyboard. No UI will be loaded and no outlets connected, only the class initializer is called automatically.
You can register a UINib (that is, a xib file). In that case the cell UI is loaded from the xib and outlets are connected.
You can create a prototype cell in the storyboard. In that case the cell is registered automatically for that specific UITableViewController or UICollectionViewController. The cell is not accessible in any other controller.
The options cannot be combined. If you have a cell prototype in the storyboard, you don't have to register again and if you do, you will break the storyboard connection.
You can assign Nib to Collection view cell with an identifier as follows :
self.collectionView.register(UINib(nibName: "nibName", bundle: nil), forCellWithReuseIdentifier: "cell")
Hope it helps.
I have a static table with one static section. Other sections are dynamic.
I create Table Section and Table Cell for dynamic section. Set identifier for Cell, set custom class for it and even do:
self.tableView.registerClass(UncheckedStoreTableViewCell.self, forCellReuseIdentifier: "StoreCell")
if i don't register it with code, then i get:
'unable to dequeue a cell with identifier StoreCell - must register a
nib or a class for the identifier or connect a prototype cell in a
storyboard'
So when i use this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 0 {
return super.tableView(tableView, cellForRowAtIndexPath: indexPath)
}
let cell = tableView.dequeueReusableCellWithIdentifier("StoreCell", forIndexPath: indexPath) as! UncheckedStoreTableViewCell
return cell
}
It works. But if i'm trying to change label: cell.myLabel.text = "one"
or just print(cell.myLabel) got
BAD_INSTRUCTION
You can definitely use dynamic cells in a static table view.
Don't expect a static table view to register your cell's identifier for you. Just do it yourself.
Do you have outlets in the cell class to some view in interface builder? If I were you I wouldn't expect the table view to know about that. It will instantiate your cell class, and that's it. No outlets will be set. I think this is related: load nib in view subclass
By the way, if you've defined a custom .nib for your cell, there's this method: registerNib(_:forCellReuseIdentifier:)
You do not need to register your cell in code.
You have correctly set the identifier of the cell, however this is not enough. In addition to this you also need to open Identity Inspector for your cell and set the class of the cell to be UncheckedStoreTableViewCell. Here is an image showing you where you should set it:
Without this step Xcode will not be able to correctly associate your cell identifier with your custom cell as it doesn't know anything about it!
I have never used UICollectionViewControllers, and I thought that they were somewhat similar to UITableViewControllers, but to my surprise, I cannot add UI elements to my custom UICollectionViewCells in the same way as I do with custom UITableViewCells.
In fact, I can add labels, buttons, etc. in the Interface Builder, but when I run the application, the cells appear empty.
I have registered the cell class during the viewDidLoad method by calling (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier, and I've checked that I am returning a valid instance of UICollectionViewCellin the (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath method.
What am I doing wrong?
My full explanation is here.
Create a custom class for the UICollectionViewCell:
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
// have outlets for any views in your storyboard cell
#IBOutlet weak var myLabel: UILabel!
}
In the storyboard make the cell use this class
And set the Identifier for the cell
Don't use the registerClass...forCellWithReuseIdentifier in viewDidLoad. But you will refer to it in collectionView...cellForItemAtIndexPath:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! MyCollectionViewCell
// Use the outlet in our custom class to get a reference to the UILabel in the cell
cell.myLabel.text = self.items[indexPath.item]
cell.backgroundColor = UIColor.yellowColor()
return cell
}
Hook up the outlets from the Views in your storyboard cell to the MyCollectionViewCell class.
#Suragch is spot on. I had this problem too: my UICollectionViewCell prototype's contents did not show in the cell when it got drawn.
The critical line is: "Don't use the registerClass...forCellWithReuseIdentifier in viewDidLoad". Really, don't. Not just "there is no need to", but "if you do register, it will stop your cell prototype from loading properly".
This only applies to Storyboard-based code, not .xib-based.
if you want to use registerClass...forCellWithReuseIdentifier, then you should do it this way:
let nib = UINib(nibName: "TrackCollectionViewCell", bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: "trackCellIdentifier")