This is my code in cellForItemAtIndexPath, where I want load cell of two collectionView. Here first one is loaded loaded perfectlly but second one is loaded properly.
} else if (collectionView == _collBanner) {
static NSString *cellIdentifier = #"bannerCell";
NSDictionary *dictBanner = [arrImages objectAtIndex:indexPath.row];
BannerCollectionViewCell *cell = (BannerCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
[cell setupBannerCell:dictBanner];
return cell;
}
return nil;
}
And my sizeForItemAtIndexPath method is...
} else if (collectionView == _collBanner) {
return CGSizeMake(_collBanner.frame.size.width -5, _collBanner.frame.size.height -2);
} else
return CGSizeMake(0, 0);
}
This line must be in viewDidLoad
[_collBanner registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
The problem is in the order of following two lines:
BannerCollectionViewCell *cell = (BannerCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
The first one asks for a cell of BannerCollectionViewCell type, but for the collectionView to be able to dequeue it, the BannerCollectionViewCell has to be registered in the collectionView. Only the second line registers the cell type to the collectionView.
First you have to register the BannerCollectionViewCell type to the collectionView:
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
And only then you can dequeue cells using:
BannerCollectionViewCell *cell = (BannerCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
However, it is enough to register the cell only once, therefore the best way is to register the cell in the viewDidLoad (move the following line from cellForItemAt to viewDidLoad):
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
Related
I have create table cell with .xib file. and added in the UITableView using following code :
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DesplayCell *cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
if (!cell) {
[tableView registerNib:[UINib nibWithNibName:#"DisplayCell" bundle:nil] forCellReuseIdentifier:#"desplayCell"];
}
//
return cell;
}
App crashes with error :
failed to obtain a cell from its dataSource
I forget to add dequeueReusableCellWithIdentifier in your code.
dequeueReusableCellWithIdentifier usage
You should use the same reuse identifier for all cells of the same form.
The reuse identifier is associated with those cells (rows) of a table view that have the same general configuration, minus cell content.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DesplayCell *cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
if (!cell) {
[tableView registerNib:[UINib nibWithNibName:#"DisplayCell" bundle:nil] forCellReuseIdentifier:#"desplayCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
}
//
return cell;
}
You can use like this
In viewDidLoad write below code
[tableView registerNib:[UINib nibWithNibName:#"DisplayCell" bundle:nil] forCellReuseIdentifier:#"desplayCell"];
In cellForRowAtIndexPath you can write below
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DesplayCell *cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
if (cell == nil) { // if cell is nil then you can alloc it
cell=[[DesplayCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"desplayCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
}
return cell;
}
The answer is like Siddhesh Mhatre post But you should make a category of UITableView, it's useful for a large project.
UITableView+Category.h
- (id)dequeueReusableOrRegisterCellWithIdentifier:(NSString *)identifier;
- (id)dequeueReusableOrRegisterCellWithClass:(Class)aClass;
UITableView+Category.m
- (UITableViewCell *)dequeueReusableOrRegisterCellWithIdentifier:(NSString *)identifier{
UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
[self registerNib:[UINib nibWithNibName:identifier bundle:nil] forCellReuseIdentifier:identifier];
cell = [self dequeueReusableCellWithIdentifier:identifier];
}
return cell;
}
- (UITableViewCell *)dequeueReusableOrRegisterCellWithClass:(Class)aClass{
UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(aClass)];
if (!cell) {
[self registerClass:aClass forCellReuseIdentifier:NSStringFromClass(aClass)];
cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(aClass)];
}
return cell;
}
Actually, I wanted to add multiple xib files to a single UIcollectionview . I have switch case to assign different collectionviewcell for different indexpath. I have not got any clear ideas how to make it possible.
CollectionCell *cell1;
switch (indexPath.row) {
case 0:
[self.Collection registerNib:[UINib nibWithNibName:#"CCollectionCell" bundle:nil] forCellWithReuseIdentifier:#"board"];
cell1 = [collectionView dequeueReusableCellWithReuseIdentifier:#"dashboard" forIndexPath:indexPath];
return cell1;
break;
}
You code style doesn't work because indexPath.row is not fixed param for the swift, so do code like below :
in viewDidLoad
[self.collectionView registerNib:[UINib nibWithNibName:#"CustomCell0" bundle:nil] forCellWithReuseIdentifier:#"MyCell0"];
[self.collectionView registerNib:[UINib nibWithNibName:#"CustomCell1" bundle:nil] forCellWithReuseIdentifier:#"MyCell1"];
// do same for all your six xib
in numberofItems
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 6;
}
in cellForItem
if(indexpath.row == 0){
CustomCell0 *cell0 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell0" forIndexPath:indexPath];
return cell0;
}
else if(indexpath.row == 1){
CustomCell1 *cell1 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell1" forIndexPath:indexPath];
return cell1;
}
:
:
else if(indexpath.row == 4){
CustomCell4 *cell4 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell4" forIndexPath:indexPath];
return cell4;
}
else
{
CustomCell5 *cell5 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell5" forIndexPath:indexPath];
return cell5;
}
You still need switch-case or if-else to specify which cell you want to load but these are some change that you can update to make you code shorter.
Move registers to viewDidLoad, you only need to call it one time:
-(void)viewDidLoad {
[super viewDidLoad];
[collection registerNib:[UINib nibWithNibName:#"CCollectionCell" bundle:nil] forCellWithReuseIdentifier:#"board"];
}
break will never be called so you can remove it too.
I found some strange happens on my table. I want to create table with two or more section, and on the first section I want to use different custom cell with the others.
So I created this on my tableView:cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
if (indexPath.section == 0) {
// cell for section one
HeaderCell *headerCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(!headerCell) {
[tableView registerNib:[UINib nibWithNibName:#"HeaderCell" bundle:nil] forCellReuseIdentifier:cellIdentifier];
headerCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
headerCell.labelName.text = #"First Section";
return headerCell;
}
else {
// Cell for another section
DetailCell *detailCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!detailSection) {
[tableView registerNib:[UINib nibWithNibName:#"DetailCell" bundle:nil] forCellReuseIdentifier:cellIdentifier];
detailCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
detailCell.textLabel.text = #"Another Section Row";
return detailCell;
}
}
On the first section, I want to use headerCell for my row, then use detailCell on the others. This code works but on the section two's row looks like still using headerCell "under" detailCell. I added label into headerCell.xib, and it still shown on the detailCell. See this image.
I think all of this because I use one cell identifier for all of section. Anyone have solution? Thank you so much.
Each type of custom cell should have its own unique identifier. Your code is attempting to use the same cell identifier for all cells. That won't work.
Also, register the two cell types in viewDidLoad, not cellForRowAtIndexPath:.
Try this:
static NSString *cellIdentifier0 = #"cell0";
static NSString *cellIdentifier1 = #"cell1";
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
// cell for section one
HeaderCell *headerCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier0 forIndexPath:indexPath];
headerCell.labelName.text = #"First Section";
return headerCell;
} else {
// Cell for another section
DetailCell *detailCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier1 forIndexPath:indexPath];
detailCell.textLabel.text = #"Another Section Row";
return detailCell;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// the rest of your code
[self.tableView registerNib:[UINib nibWithNibName:#"HeaderCell" bundle:nil] forCellReuseIdentifier:cellIdentifier0];
[self.tableView registerNib:[UINib nibWithNibName:#"DetailCell" bundle:nil] forCellReuseIdentifier:cellIdentifier1];
}
I have two types of UICollectionViewCell : one is gallery cell and another is recipe cell.
There is a toggle button.
First time the view loads, gallery cell is used to display in collection view.
But on clicking the toggle button, I tried to load another cell:(recipe cell) but it crashed saying there is no property(actually this is the property of recipe cell) in gallery cell.
Is there a way to load same collection view with another cell??
Thanks in advance.
EDIT:
if (isGalleryOnCollectionView) {
ProfileFollowerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
NSString *followerName;
if ([[arr_followerNames objectAtIndex:indexPath.row] isEqualToString:#""]) {
followerName=[arr_followersEmail objectAtIndex:indexPath.row];
}
else{
followerName=[arr_followerNames objectAtIndex:indexPath.row];
}
NSLog(#"\n\n\n follower name is :: %#\n\n",followerName);
cell.lbl_followerName.text = followerName;
}else{
GalleryCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.lbl_recipeName.text = [[[dict_profileData valueForKey:#"recipes"] valueForKey:#"name"] objectAtIndex:indexPath.row];
}
SOLUTION:
[self.profleCollectionView registerClass:[ProfileFollowerCell class] forCellWithReuseIdentifier:#"followercell"];
After registering from the nib before dequeuing reusable identifier it works.
Here is a good tutorial on creating custom UICollectionViewCell with xibs.
What your missing is having this in your -(void)viewDidLoad
UINib *cellNib = [UINib nibWithNibName:#"ProfileFollowerCellNib" bundle:nil];
[self.collectionView registerNib:cellNib forCellWithReuseIdentifier:#"TheNibCellIdentifier"];
You also need to make sure to use the respective ReuseIdentifier when loading the cell:
ProfileFollowerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"TheNibCellIdentifier" forIndexPath:indexPath];
Before I created custom cell for UITableView I used this to render rows:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
Then I have created CustomCell with two UILabels in it.
And replace code from above with:
static NSString *CellIdentifier = #"customCell";
OrderCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
[tableView registerNib:[UINib nibWithNibName:#"MyCustomCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
But now accessory is not visible.
It shows only at first row and it doesn't look like before.
Is there anything else that I need to do to show accessory when creating custom cell?
Modify your code as below. Set the accesssory Type outside of condition..
static NSString *CellIdentifier = #"customCell";
OrderCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
[tableView registerNib:[UINib nibWithNibName:#"MyCustomCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
You have set the accessoryType inside the condition if(cell==nil) which calls first time..
Hope it fix the issue..
If you're using storyboard, then you have to register your custom nib in viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"YourClass" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"YourCellIdentifier"];
}
If you're not using storyboard, you have to register it in your cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"YourCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if(!cell)
{
cell = [[[NSBundle mainBundle] loadNibNamed:#"YourCustomClass" owner:self options:nil] lastObject];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
////
return cell;
}
You have to register your nib in viewDidLoad instead of cellForRowAtIndexPath
- (void)viewDidLoad
{
[super viewDidLoad];
static NSString *CellIdentifier = #"customCell";
[tableView registerNib:[UINib nibWithNibName:#"MyCustomCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
}