How to use custom UICollectionViewCell within Storyboard? - ios

I don't understand why the custom cell is not recognised in the Storyboard.
TNTopStoriesCollectionViewController:
static NSString * const reuseIdentifier = #"TNTopNewsCellItem";
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
TNTopStoriesCollectionViewCell *cell = (TNTopStoriesCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell
[self preLoadImagesForCategory:_dataStore.fiveTopStories[indexPath.item] andImageView:cell.itemImage];
return cell;
}
I'm using a storyboard for the collectionView:
And the cell is also correctly pointing to the custom class:
#import <UIKit/UIKit.h>
#interface TNTopStoriesCollectionViewCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *itemImage;
#property (weak, nonatomic) IBOutlet UILabel *title;
#end
And the correct cell identifier is also used:
And yet I get this exception within cellForItemAtIndexPath method:
[UICollectionViewCell itemImage]: unrecognized selector sent to instance
But why please?
Update:
I did everything as suggested and am now getting this:
However it still fails at the same spot. :(

The fact that this cell is called "Collection View Cell" on the left, in the hierarchical name listing of objects in the scene, and has not changed to "Top Stories Collection View Cell" suggests that you have not actually changed its class in the storyboard to TNTopStoriesCollectionViewCell successfully.
(Notice how the collection view controller is listed on the left as Top Stories Collection View Controller. The same kind of thing should have happened to the cell.)
What you see on the left should look more like this:
(Also, the fact that your label outlet is called News Label on the left is suggestive of a problem, since in code this label is called "title", and if you've hooked that up correctly I'd expect Xcode to have changed its name to "title" in the listing on the left as well.)
[I have a vague feeling that you may actually have two classes, TNTopStoriesCollectionViewCell and TNTopNewsCellItem, and you've confused yourself about them...]

In storyboard, there is another way to create Custom
CollectionViewCell.That is Separately create the new
file(CustomCellCollectionViewCell.h,CustomCollectionViewCell.m and
CustomCollectionViewCell.xib) through the IOS->Source->Cocoa Touch
Class->SubClass of UICollectionViewCell and give name in Class. After
that you can import the the .h of CustomCollectionViewCell and also
you need to register that in viewDidLoad.
- (void)viewDidLoad
{
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
UINib *cellNib = [UINib nibWithNibName:#"CustomCollectionViewCell" bundle:nil];
[collectionViewSelection registerNib:cellNib forCellWithReuseIdentifier:#"customCollectionCell"];
}
Then
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"customCollectionCell";
CustomCollectionViewCell *cell = (CustomCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
return cell;
}

Related

Subclassing custom UICollectionViewCell

I've succesfully created custom UICollectionViewCell that has 3 labels.
Now I want to subclass it, add dateToDisplay property and in setDateToDisplay change labels's strings (with custom date formatters).
Creation and usage of parentCell:
ParentCellIdentifier.h
static NSString *ParentCellIdentifier = #"ParentCellIdentifier";
#interface ParentCell : UICollectionViewCell
#property (strong, nonatomic) IBOutlet UILabel *firstLabel;
#property (strong, nonatomic) IBOutlet UILabel *secondLabel;
#property (strong, nonatomic) IBOutlet UILabel *thirdLabel;
-(void)setupDefaults;
#end
In parentCell.xib:
Class set to ParentCell and Identifier set to ParentCellIdentifier
In ViewController I have UICollectionView:
-(void)setupCollectionView {
[_daysCollectionView registerNib:[UINib nibWithNibName:#"ParentCell" bundle:nil] forCellWithReuseIdentifier:ParentCellIdentifier];
_daysCollectionView.delegate = self;
_daysCollectionView.dataSource = self;
_daysCollectionView.backgroundColor = [UIColor clearColor];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ParentCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ParentCellIdentifier forIndexPath:indexPath];
cell.firstLabel.text = #"first";
cell.secondLabel.text = #"second";
}
The setup above worked like a charm.
No I want to add ChildCell, using same xib as previously:
#interface ChildCell : ParentCell
#property (nonatomic, strong) NSDate* dateToDislpay;//labels of parentCell updated using dateformatters on setDateToDisplay:
#end
-(void)setupCollectionView left the same, registering ParentCell.xib for ParentCellIdentifier
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ChildCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ParentCellIdentifier forIndexPath:indexPath];
NSDate* date = [_dates objectAtIndex:indexPath.row];
cell.dateToDislpay = date; //here goes the error
When trying to set property of child cell, it crashes. It's correct, because in ParentCell.xib class of the cell is ParentCell.
After changing the class in xib, it works, but I want to stick with my parent class in xib, since I will use the same xib, but with different formatters only.
How can I do it?
EDIT1:
crash received:
-[ParentCell setDateToDislpay:]: unrecognized selector sent to instance
You need to go into the xib file and change the class type to ChildCell and that should fix your crash.
To subclass see here: https://stackoverflow.com/a/5056886/848719
You'll have to override initWithFrame: and awakeFromNib.
You got crash because you have register [UINib nibWithNibName:#"ParentCell" bundle:nil] Parent Cell and in cell for item you are create object of ChildCell , but it is parent cell not child cell
and parent cell does not have dateToDislpay property .
you can check same with print class
you are doing inheritance wrong way, you should read some tutorial or read some demos

Embed UITableView in UITableViewCell in iOS 9, Xcode 7 and Storyboards

I have two UITableViews using Storyboards in Xcode 7. I've set the delegate and dataSource using the Connections Inspector for both table views.
Let the first table view be the main table view and let the table views within each cell of the main table view be the detail table views with cell identifiers named appropriately and respectively.
When [tableView dequeueReusableCellWithIdentifier:#"MainCell" forIndexPath:indexPath] executes, it immediately calls its dataSource method -cellForRowAtIndexPath: for DetailCell preventing me from setting a custom instance variable in time to add the appropriate data to each cell.
The following is a simplified example marked using comments.
MainTableViewController:
#implementation MainTableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Keep in mind the following two (2) lines are set using the Connections Inspector
//cell.detailTableView.dataSource = cell;
//cell.detailTableView.delegate = cell;
// Stepping over the following line will jump to the
// other `-cellForRowAtIndexPath:` (below) used to set
// the detail info.
cell = (MainTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"MainCell" forIndexPath:indexPath];
CustomObj *obj = self.mainData[indexPath.row];
cell.nameLabel.text = obj.name;
cell.additionalInfo = obj.additionalInfo; // This line is not set before instantiation begins for the detail table view...
return cell;
}
...
#end
DetailTableViewCell (contains a UITableView and implements appropriate protocols):
#interface DetailTableViewCell : UITableViewCell <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) IBOutlet UILabel *nameLabel;
#property (nonatomic, weak) IBOutlet UITableView *detailTableView;
#property (nonatomic, strong) CustomObj *additionalInfo;
#end
#implementation DetailTableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell = (DetailTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCell" forIndexPath:indexPath];
// Instantiate detail ...
cell.detailLabel.text = self.additionalInfo.text;
// Problem!
// self.additionalInfo == nil thus we cannot set a value to the label.
return cell;
}
...
#end
The problem is when the detail -cellForRowAtIndexPath: method is called, I haven't had a chance to set a value for its dataSource, in this case, additionalInfo.
There are many possible ways to fix your problem, but first I would say that, your design seems not a good one, A UItableViewCell has another UITableView, and another UItableViewCell inside this UITableView? Why you do this? Just use one UITableView and put all of your views into one UItableViewCell as subViews should be enough.
Now get to your problem:
I would suggest not to use IBOutlet for setting up your delegate and dataSource, use code. This can give you a chance to delay setting the dataSource and delgate when you are ready. Once you think it's the proper time, just call [cell.detailTableView reloadData] will trigger your DetailTableViewCell to invoke cellForRowAtIndexPath
#implementation MainTableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Keep in mind the following two (2) lines are set using the Connections Inspector
//cell.detailTableView.dataSource = cell;
//cell.detailTableView.delegate = cell;
// Stepping over the following line will jump to the
// other `-cellForRowAtIndexPath:` (below) used to set
// the detail info.
cell = (MainTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"MainCell" forIndexPath:indexPath];
CustomObj *obj = self.mainData[indexPath.row];
cell.nameLabel.text = obj.name;
cell.additionalInfo = obj.additionalInfo; // This line is not set before instantiation begins for the detail table view...
// setup dataSource and delegate now
cell.detailTableView.dataSource = cell;
cell.detailTableView.delegate = cell;
// call reloadData whenever you think is proper
[cell.detailTableView reloadData];
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = nil;
//Check this call is for which table view.
if(tableView == detailTableView) {
cell = (MainTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"MainCell" forIndexPath:indexPath];
// Do any additional setup you want with MainCell
} else {
cell = (DetailTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCell" forIndexPath:indexPath];
// Do any additional setup you want with DetailCell
}
return cell;
}

UISearchBar with UITableView containing custom cells => blank cells

I have a UITableView containing custom cells. All works fine. But after, I decided to add a searchBar in order to... Search !
So, I added a "Search Bar and Search Display Controller" from the "Object Library" in my xib file, under the UITableView.
I created a specific class for the custom cell :
"CustomCell.h"
#class CustomCell;
#interface CustomCell : UITableViewCell
{
}
#property (weak, nonatomic) IBOutlet UILabel *lblDate;
#property (weak, nonatomic) IBOutlet UILabel *lblAuteur;
#end
"CustomCell.m"
no interesting stuff
"CustomCell.xib"
The "Event" class :
#interface Event : NSObject
{
}
#property (strong, nonatomic) NSString *desc;
#property (strong, nonatomic) NSString *dateCreation;
#end
And the view containing the UITableView and the UISearchBar :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
// Determinate the current event
Event *currentEvent;
if (tableView == self.searchDisplayController.searchResultsTableView)
currentEvent = [filteredArray objectAtIndex:indexPath.row];
else
currentEvent = [notFilteredArray objectAtIndex:indexPath.row];
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil)
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.lblAuteur.text = [currentEvenement desc];
cell.lblDate.text = [currentEvenement dateCreation];
return cell;
}
Ok, now we can come to my problem. After loading the tableView, the custom cells are displaying well. But not if I use the SearchBar :
If there is an event with the desc attribute equal to "foo", and if I enter "bar" in the SearchBar, I obtain the "No results" message. It's normal.
If there is an event with the desc attribute equal to "foo", and if I enter "foo" in the SearchBar, the cells are displaying, but without their content ! I'm just seeing the cells' borders, and the lblDate and the lblAuteur are equal to nil.
Why have I this behaviour ? Thanks a lot for your help... I precise that the filteredArray and the notFilteredArray are correctly filled (I checked that many times). It means that the search mechanism is working well.
After much "searching" (pun) I've found the problem.
When you reference the tableview with the prototype cell you can't rely on the tableview that is passed in because sometimes that tableview is the search tableview without the prototype cell.
so instead of...
HomeTabCell *cell = (HomeTabCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
replace the "tableview" above with a direct connection to the table view with the prototype cell
HomeTabCell *cell = (HomeTabCell *)[self.HomeTableView dequeueReusableCellWithIdentifier:CellIdentifier];
Hope this helps!
Check these settings, if there not
self.searchDisplayController.searchResultsDelegate = self;
self.searchDisplayController.searchResultsDataSource = self;
try this,
Sorry for people searching to resolve this issue...
I could not fix it, and the prime contractor do not want this function anymore, so I gave up.

UITableViewCell with xib

I'm developing an app for iOS which use the xib files.
Usually I use Storyboard and I don't know how to set up a UITableViewCell with xib files. When I make a xib file with a UITableView, I see a table with some row, now I need to edit this row to write what I stored in an array.
How can I use the xib file to design a UITableViewCell?
I need to do a very simple table: I would to use the Basic preset for the cell to display a title.
I know that I've to connect the delegate and DataSource to the file owner for table view and I put in the file owner the UITableViewDelegate and UITableViewDataSource.
Now how I can edit the content of the cell?
I found on the web some guide that tells to create a xib file with a UITableViewCell and I did it, but I don't know how to work with this
Firstly, you need to create the class for the customCell which inherits from UITableViewCell.
Now, add the properties you want to have in your customCell. In this example I added cellImage and cellLabel.
#property (nonatomic, strong) IBOutlet UILabel *cellLabel;
#property (nonatomic, strong) IBOutlet UIImageView *cellImageView;
After that you need to link the UILabel and the UIImageView from the CustomCell to the Nib.
You need to add:
- (void)viewDidLoad
{
....
[self.tableView registerNib:[UINib nibWithNibName:#"xibName" bundle:nil] forCellReuseIdentifier:CellIdentifier];
.....
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCellReuse";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
[cell.cellImageView setImage:[UIImage imageNamed:#"whatever"]];
[cell.cellLabel setText = #"whatever"];
return cell;
}

How to set a UILabel in UICollectionViewCell

I have an app with a UIViewController with a UICollectionView IBOutlet in it.
The cell in the UICollectionView is MyCustomCell and has this method setting its UILabel:
-(void)setCellLabel:(NSString *)value{
NSLog(#"settinglabel");
cellLabel.text = #"hardcode"; //added for testing purposes
}
The cell has the property Class type identifying it as MyCustomCell in storyboard and its dequeue identifier as well. The UIViewController adopts the datasource and delegate protocols. The IBOutlet UILabel has its cellLabel outlet connected to the storyboard. The methods are defined as:
- (void)viewDidLoad{
[super viewDidLoad];
self.restNames = #[#"Orange",#"Naranja",#"Narnia"];
[self.collectionView registerClass:[MyCustomCell class] forCellWithReuseIdentifier:#"MyCustomCellID"];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
NSLog(#"%d",[self.restNames count]);
return [self.restNames count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MyCustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
[cell setCellLabel:#"hi"];
NSLog(#"fitsname %#",[self.restNames objectAtIndex:indexPath.row]);
return cell;
}
I get three cells drawn in my tableview, corresponding to the 3 objects in my array. The array simply contains string objects which I was setting directly by objectAtIndexPath but I decided to set it directly to #"hi" since it wasn't working. I even changed the value used in setCellLabel method to a hardcoded value and I keep get just the "Label" default string in each cell.
Why isnt the cellLabel being set properly?
Do you have your cellLabel outlet set in interface builder?
You should have something like this in your cell's .h file:
#property (weak, nonatomic) IBOutlet UILabel *cellLabel;
then later you really just need to do this:
cell.cellLabel.text = #"";
When you're using Storyboard, the default template is wrong, because it uses the line
[self.collectionView registerClass:[UICollectionView class] forCellWithReuseIdentifier:CellIdentifier];
But the storyboard already registered it. So basically this is what you have to do to create a custom, storyboard based UICollectionView :
Create your UICollectionViewController subclass
Click&drag a UICollectionViewController to the storyboard and change the configuration as you want
Create a UICollectionViewCell subclass
Set the cell class in the storyboard, set it's reuse identifier ctrl-drag the needed outlets
Remove the [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier: CellIdentifier];
Set the static reuse identifier in the UICollectionView subclass
You have probably forgotten to tell your UICollectionView what class it’s supposed to use to create cells. This is done with the following line of code:
[self.collectionView registerClass:[MyCustomCell class] forCellWithReuseIdentifier: CellIdentifier];
You can set this at the end of the viewDidLoad of your controller.

Resources