In my app I need to expand the tableviewcell when the user taps on a particular button(which is like a toggle, tapping will expand the row and taping other time will collapse the row) in that cell. So I have implemented the custom delegate method to know which cell need to get reloaded and reload that particular cell with 'reloadRowsAtIndexPaths'.
It works fine while tapping the button for first time, and even for the second time, but its getting crashed by the third time saying 'Could not load NIB in bundle: 'NSBundle </Users/path/myApp.app> (loaded)' with name 'ContactCell''.
My question is reloading of the cell which works for first time and second time why its crashing for third time?
My Code:
[contactTableView beginUpdates]; // Inside the custom delegate method
[contactTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexpath] withRowAnimation:UITableViewRowAnimationNone]; // indexpath is which i get from cell through custom delegate method
[contactTableView endUpdates];
ContactTableCell *cell; //Inside the cellForRowAtIndexPath
static NSString *CellIdentifier = #"ContactCell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// load a new cell from the nib file
[[NSBundle mainBundle] loadNibNamed:#"ContactCell" owner:self options:nil];
cell = self.contactCell;
cell.delegate = self;
cell.indexPath = indexPath;
self.contactCell = nil;
}
Why is it crashing?
Ok there are a couple of problems with this. Firstly, loading from the nib should not be in this class it should be in the ContactTableCell class in an init method (initWithNib or what you want to call it)
Your XIB needs to make sure that ContactTableCell is the custom class assigned to it also.
so your init with nib would go something like this
//in ContactTableCell.m
-(id)initWithNib{
self = [[[NSBundle mainBundle] loadNibNamed:#"ContactCell" owner:self options:nil] firstObject];
if(self){
//do extra customisation stuff/ set labels etc.
}
return self;
}
Then you would call
if (cell == nil) {
// load a new cell from the nib file
cell = [[ContactTableCell alloc] initWithNib];
cell.delegate = self;
cell.indexPath = indexPath;
}
Register you nib in viewDidLoad once.
NSString *cellIdentifier=#"cellIdentifier";
UINib *nib=[UINib nibWithNibName:cellIdentifier bundle:[NSBundle mainBundle]];
[self.yourTableView registerNib:nib forCellReuseIdentifier: cellIdentifier];
Hope this will work
Related
I'm designing my application,As per the design tableView should load any custom cell based on the reusable identifier.
From webservice tableView will get will get list of reusable identifiers and tableView will load all cells as per the identifier.
Here is my cellForRowAtIndex method
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[_cardsIdentifier objectAtIndex:indexPath.row]];//_cardsIdentifier is array of identifiers
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:[_cardsIdentifier objectAtIndex:indexPath.row] 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];
}
NSLog(#"%#",cell.reuseIdentifier);
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
As one can see i'm using same identifier for nib name as well.
It will work fine when reusable identifier and nib name is same,but it will crash if nib name is different from reusable identifier.
Can anyone suggest how can i remove this dependency of nib name.
Register your cell class
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:cellIdentifier];
And in your cellForRowAtIndexPath
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
You can set identify in .xib files.
I am making a custom ui table view cell. I know i can use loadNibNamed method to use .xib
of the cell but that causes scrolling to be slow when my I have too much data in it .
I want to use UI nib because its lot faster than loadNibNamed method for loading custom cell .xib file .
static NSString *cellIdentifier = #"PostStreamCell";
PostStreamCell *cell= [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PostStreamCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
UINib *cellNib = [UINib nibWithNibName:#"MemberCell" bundle:nil];
[cell.collectionView registerNib:cellNib forCellWithReuseIdentifier:#"MemberCell"];
}
cell.textlabel.text =#"xyzabc123";
I tried using code below in above "if "block but failed to use it. Any help would be appreciated.
UINib *cellNib = [UINib nibWithNibName:#"PostStreamCell" bundle:nil];
[cell registerNib:cellNib forCellWithReuseIdentifier:#"PostStreamCell"];
Create your xib file with a UITableViewCell as the top-level object. This is called Cell.xib
Create a UINib object based on this file
Register the UINib with the table view (typically in viewDidLoad of your table view controller subclass).
use the following line in viewDidLoad:
[self.tableView registerNib:[UINib nibWithNibName:#"Cell" bundle:nil] forCellReuseIdentifier:#"Cell"];
Then, in cellForRowAtIndexPath, if you want one of the cells from the nib, you dequeue it:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
This either creates a new instance from the nib, or dequeues an existing cell.
You only need to register the Xib once, so this regiserNib code should go within the viewDidLoad method of your class file
UINib *cellNib = [UINib nibWithNibName:#"PostStreamCell" bundle:nil];
[self.tablview registerNib:cellNib forCellWithReuseIdentifier:#"PostStreamCell"];
Then within your cellForRowAtIndexPath method of your tableview
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"PostStreamCell";
PostStreamCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.textlabel.text =#"xyzabc123";
}
This will work for you as you need it.
Cheers
Edit in response to PostStreamCell error*
Please make sure your custom UITableViewCell xib has the 'PostStreamCell' identifier, which you can set in this part of the IB
Please note the xib is a UITableViewCell object.
Update - pic showing where to check custom class files associated with xib
Within the Utilities of the IB, please make sure your custom UITableViewCell uses your custom class files PostStreamCell. Please check they're shown in this part of the IB.
Also within your UIViewController class files, (where you have the UITableView methods etc) make sure to
#import "PostStreamCell.h"
I have an app built for iOS 5 that I'm trying to upgrade straight to iOS 7, so this also maybe an issue with iOS 6.
We have a UITextField inside a custom table view cell (class derived from UITableCellView), but tapping on it no longer brings up the keyboard in the simulator. Everything is enabled, and User Interaction Enabled is checked.
It used to work fine in iOS 5.
I'm not sure what code to include, but here's the code that creates the cell... the LoginRegisterTableViewCell just has a 'fieldLabel' (UILabel) and 'userText' (UITextField):
// Login area
static NSString * reuseIdentifier = #"LoginRegisterTableViewCell";
LoginRegisterTableViewCell * cell = (LoginRegisterTableViewCell *)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(cell == nil)
{
// The official Apple way of loading TableViewCell nibs
// http://www.nomadplanet.fr/2011/01/custom-uitableviewcells-loaded-from-xib-howto-debug/
[[NSBundle mainBundle] loadNibNamed:#"LoginRegisterTableViewCell" owner:self options:nil];
cell = formFieldCell;
self.formFieldCell = nil;
}
cell.delegate = self;
cell.userText.tag = [indexPath row];
I can get the keyboard to come up if I call [userText becomeFirstResponder] when the table cell is selected, but this seems like a workaround as opposed to the correct way.
Try this code with the table view data source: cellForRowAtIndexPath
NSString *cellReuseIdentifier = #"CellIdentifier";
UINib *nib = [UINib nibWithNibName:#"CustomTableViewCell" bundle:nil];
[_myTableView registerNib:nib forCellReuseIdentifier:cellReuseIdentifier];
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (!cell)
{
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
}
return cell;
It is working for me with the custom cell created with the xib as shown in the image
Note: Mark Also create XIB file.
And give a cell reuse identifier like
This is working for me well for the sample application with no issue with the keyboard.
I'm having a hard time understanding the following block of code inside cellForRowAtIndexPath:
NSString *uniqueIdentifier = #"SliderCellWithComments";
SliderCellWithComment *cell = nil;
cell = (SliderCellWithComment*) [tableView dequeueReusableCellWithIdentifier:uniqueIdentifier];
if(!cell)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"SliderCellWithComment" owner:nil options:nil];
for (id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[SliderCellWithComment class]])
{
cell = (SliderCellWithComment*)currentObject;
cell.delegationListener = self; //important!!
cell.indexPath = [indexPath copy]; //important!!
break;
}
}
[cell setNameLabelText:#"Days to display:"];
.
.
.
I got this code from StackOverflow and it worked fine until I tried running it on iOS 5.1, where it crashes with an error: 'NSInternalInconsistencyException', reason: 'The NIB data is invalid.'
But what I do not understand about the code is that it doesn't seem to really re-use anything.
For instance:
Why does this code assign a value to "cell" twice?
cell=(SliderCellWithComment*)[tableView dequeueReusableCellWithIdentifier:uniqueIdentifier];
cell = (SliderCellWithComment*)currentObject;
If 2 executes, according to me, nothing is being re-used since the cell is assigned a value from new nib.
I don't really get the use of the Array either, why does the following code render blank cells:
static NSString *CellIdentifier = #"SliderCellWithComments";
SliderCellWithComment *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[SliderCellWithComment alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
[cell setNameLabelText:#"Days to display:"];
cell.delegationListener = self; //important!!
cell.indexPath = [indexPath copy]; //important!!
.
.
.
Actually the code is reusing cells. [tableView dequeueReusableCellWithIdentifier:uniqueIdentifier]; is asking the table view if he can find a cell with that identifier that can be reuse, if there is a cell that can be reused then the cell will not be nil and the code from the if(!cell){} will not be executed, if the table doesn't find a cell then the if(!cell){} block will be executed and a new custom cell will be created from a xib file.
I don't really get the use of the Array
What you are having there (that array) is a default way of loading a custom view from a xib file.
why does the following code render blank cells
Because in that piece of code you are calling a method from UITableViewCell that is probably not implemented in your custom cell because the custom cell initialization will be done using the xib file (that array that is mentioned in the first quote:)
how would i use UINibs to instantiate and use a UITableViewCell for a tableview in iOS5.0. I know there is a registerNib:forCellReuseIdentifier: in iOS5.0 that also needs to be used, but am not sure how to use it
Thanks in advance for any help on this
Create your xib file with a UITableViewCell as the top-level object. This is called Cell.xib
Create a UINib object based on this file
Register the UINib with the table view (typically in viewDidLoad of your table view controller subclass).
Steps 2 and 3 can be combined, so you would use the following line in viewDidLoad:
[self.tableView registerNib:[UINib nibWithNibName:#"Cell" bundle:nil] forCellReuseIdentifier:#"Cell"];
Then, in cellForRowAtIndexPath, if you want one of the cells from the nib, you dequeue it:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
This either creates a new instance from the nib, or dequeues an existing cell.
#jrturtons answer is correct but unfortunately there's a bug in iOS 5 (fixed in iOS 6) in conjunction with VoiceOver: rdar://11549999. The following category on UITableView fixes the issue. Just use -fixedDequeueReusableCellWithIdentifier: instead of the normal dequeueReusableCellWithIdentifier:. Of course, the NIB must be registered using
[self.tableView registerNib:[UINib nibWithNibName:#"Cell" bundle:nil] forCellReuseIdentifier:#"Cell"];
before (in -viewDidLoad).
UITableView+Workaround.m:
#implementation UITableView (Workaround)
- (id)fixedDequeueReusableCellWithIdentifier:(NSString *)identifier {
id cell = [self dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
// fix for rdar://11549999 (registerNib… fails on iOS 5 if VoiceOver is enabled)
cell = [[[NSBundle mainBundle] loadNibNamed:identifier owner:self options:nil] objectAtIndex:0];
}
return cell;
}
#end