I have a custom UITableViewCell that's loaded from a nib. I can pull this into my app with a reuseIdentifier by performing the following steps:
1) Set the reuse identifier in the Nib as "CustomCellIndentifier"
2) Register the nib:
[[self tableView] registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"CustomCellIndentifier"];
3) Return the cell in tableview:cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCellIndentifier"];
return cell;
}
My question is, how can I return a cell WITHOUT a reuse identifier? I have a small table and I don't want the cell to be reused (it messes up some subviews I have in the cell if I scroll).
I've tried a combination of setting the above 3 reuse identifiers to nil and they all generate errors.
I've also tried this below, but the cell contents reset if I scroll past the cell and I get an error message "no index path for table cell being reused":
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
return cell;
}
I think this is not a good way, but as per your requirement Use this:
Write the init method in your CustomCell class
- (id)init
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"QuestionOptionCell" owner:self options:nil];
CustomCell *theEditView = [nibObjects objectAtIndex:0];
self = theEditView;
theEditView = nil;
return self
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [[CustomCell alloc] init];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
return cell;
}
Related
At first I had this code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DropDownTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DropDownTableViewCell"];
if (!cell) {
NSArray *topLevelObjects =
[[NSBundle mainBundle] loadNibNamed:#"DropDownView"
owner:self
options:nil];
for (DropDownTableViewCell *object in topLevelObjects) {
if ([object class] == [DropDownTableViewCell class]) {
cell = object;
break;
}
}
NSAssert(cell, #"Cell must not be nil");
}
cell.nameLabel.text = [self.dataSource buttonDownPicker:self stringForRowAtIndexPath:indexPath];
return cell;
}
At first moment when I show tableView and tableView cell's starts loading from nib I have UI freezing for a few seconds (caused by loading from nib for EVERY displayed cell). This can be solved by loading cell from nib earlier:
- (void)awakeFromNib {
DropDownTableViewCell *cell = [[[NSBundle mainBundle] loadNibNamed:#"DropDownView" owner:self options:nil] objectAtIndex:0];
}
But this way looks "hacky". Is there more appropriate solution?
Edit according to given answers:
I've tried to use registerNib forCellIdentifier but it didn't LOAD nib, it just BINDING nib with identifier and at first time when tableView appears all cells causing load nib to memory
This is not "hacky" at all. For loading cells from a nib what you usually do is load the nib and then register the cell for reusable identifier of your choosing. For instance in one of my projects I have a view controller with a table view. In the view did load I call:
[[NSBundle mainBundle] loadNibNamed:#"ChannelListCell" owner:self options:nil];
[self.channelListTableView registerNib:[UINib nibWithNibName:#"ChannelListCell" bundle:nil] forCellReuseIdentifier:#"channelListCell"];
Then in the cell for row at index path:
cell = [tableView dequeueReusableCellWithIdentifier:#"channelListCell" forIndexPath:indexPath];
In your case the dequeued cell is always nil since you did not register it.
Try like this.....
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UINib *nib = [UINib nibWithNibName:#"" bundle:nil];
[self.tblview registerNib:nib forCellReuseIdentifier:#"DropDownTableViewCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
DropDownTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DropDownTableViewCell"];
return cell;
}
You can register your class first like bellow in your viewDidLoad. It make faster and better
[self.tableViewObject registerClass: [DropDownTableViewCell class]forCellReuseIdentifier:#"DropDownTableViewCellIdentifier"];
And please add following method in your DropDownTableViewCell.m file
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"DropDownTableViewCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
self = [topLevelObjects objectAtIndex:0];
return self;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier=#"DropDownTableViewCellIdentifier";
DropDownTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
//Access all cell properties here.
return cell.
}
Please refer https://stackoverflow.com/a/30954273/914111 for better knowledge.
I've a custom UITableViewCell subclass and I've read that this is supposed to be the correct way of loading custom cells for iOS 5:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"customCell"];
// Configure cell
cell.nameLabel.text = self.customClass.name;
}
return cell;
}
But the label text is not shown when I run the app. However, I also tried this way:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
if (cell == nil) {
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
for (UIView *view in views) {
if([view isKindOfClass:[UITableViewCell class]])
{
cell = (CustomCell *)view;
}
}
// Configure cell
((CustomCell *)cell).nameLabel.text = self.customClass.name;
}
return cell;
}
This way the label is displayed, but any reuseIdentifier is set in loadNibName: method. What the best way of loading custom cells should be? I need to support iOS 5+. Could the first approach not be working because I'd to configure cell's labels and styles in initWithStyle: method and not in the table view's method?
Thanks!
The error in your code is that cell.nameLabel.text is only set in the if (cell == nil) { ... } case and not generally.
The easiest ways to load custom cells are
Use registerNib:forCellReuseIdentifier: if the cell is defined in a nib file, or
use registerClass:forCellReuseIdentifier: if the cell is created programmatically, or
use a Storyboard and define "CustomCell" as "Prototype Cell" for the table view.
For example (in viewDidLoad):
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"customCell"];
Then dequeueReusableCellWithIdentifier
will always return a cell, so that cellForRowAtIndexPath simplifies to
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
cell.nameLabel.text = self.customClass.name;
return cell;
}
Just use this code and try.
static NSString *cellIdentifier=#"cell";
YourCustomCell *cell = (YourCustomCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
NSString *customeCellName = [NSString stringWithFormat:#"%#",[YourCustomCell class]];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:customeCellName owner:self options:nil];
for (id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (YourCustomCell *) currentObject;
break;
}
}
}
cell.nameLabel.text = self.customClass.name; // Make sure self.customclass.name have value.
return cell;
Use this code (NewCustomCell is your Custom UITableViewCell class name)...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NewCustomCell *cell = (NewCustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib=[[NSBundle mainBundle]loadNibNamed:#"NewCustomCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
}
return cell;
}
Happy coding... :)
I am getting EXC_BadAccess error message while i am scrolling tableview.
the following is the code i have done in cellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier=#"customCellHistory";
customCellHistory *cell=(customCellHistory*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects=[[NSBundle mainBundle]loadNibNamed:#"customCellHistory" owner:self options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[UITableViewCell class]] ) {
cell=(customCellHistory*)currentObject;
break;
}
}
}
cell.lb11.text=[cellArray1 objectAtIndex:indexpath.row];
cell.lbl2.text=[cellArray2 objectAtIndex:indexpath.row];
return cell;
}
I can sense the problem is arising due to some mistake in the above code.
I used CustomCell in the above code to display a customized cell.
can anyone tell me what wrong have i done in this code
Hey try the following code, dont forget to set the cell identifier in you custom XIB to customCellHistory
At the top
#import "customeCellHistory.h"
then
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"customCellHistory";
customCellHistory *cell = (customCellHistory *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"customCellHistory" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.lb11.text=[cellArray1 objectAtIndex:indexpath.row];
cell.lbl2.text=[cellArray2 objectAtIndex:indexpath.row];
return cell;
}
The problem seems to arise from the strange loop you have. Use the last object method to set cell from the nib.
You are reusing a cell and then changing the cell in your loop which probably leads to a cell not existing where you are looking.
if (cell == nil) {
NSArray *topLevelObjects=[[NSBundle mainBundle]loadNibNamed:#"customCellHistory" owner:self options:nil];
You don't need that code. Just register the nib with the table view, earlier on:
[self.tableView registerNib:[UINib nibWithNibName:#"customCellHistory" bundle:nil]
forCellReuseIdentifier:#"customCellHistory"];
Now when you call dequeueReusableCellWithIdentifier, the nib will be loaded and the cell will be delivered, if there is no spare cell in the reuse pile. This ensures that you consistently have a cell and that it is the right kind of cell. Use the methods the framework gives you.
I really can't understand why i get a "EXC_BAD_ACCESS" in the line where I assign NSArray *topLevelObjects. It's crazy because I use exactly the same code and the same BlogCell in another tabliView, and there it's working perfectly!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int r = indexPath.row;
static NSString *CellIdentifier = #"Blog";
BlogCell *cell = (BlogCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"BlogCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
return cell;
}
Make sure all the outlets you specify in BlogCell to FilesOwner have corresponding IBOutlets in this class.
When I run my ios app, only the first cell displays in the TableView, then when clicked the second cell displays. I would like them both to display at the same time, but I cannot figure out this behavior.
Here is the code for my view did load
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ProductCellId";
ProductTableCell *cell =
(ProductTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"ProductTableCell" owner:self options:nil];
cell = self.productCell;
}
Product *product = [products objectAtIndex:indexPath.row];
[cell configureForProduct:product];
return cell;
}
Any help would be much appreciated!
Since you are loading your cell from Interface builder try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ProductTableCell"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"ProductTableCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
}
Product *product = [products objectAtIndex:indexPath.row];
[cell configureForProduct:product];
return cell;
}
Change this:
static NSString *CellIdentifier = #"ProductCellId";
to:
static NSString *CellIdentifier = #"ProductTableCell";
You can find additional information for what you are trying to do in this question: Load cells from XIB files