Custom Cell re-use in iOS 5.1 - uitableview

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:)

Related

How to load a custom UITableViewCell without using nib name

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.

hold data on tableview cell ios

I'm newbie in IOS and again i face another issue. How can i prevent data vanish from a table cell when i scroll a tableview.
I'm using the code below to load data on the table...Works fine but the data disappear when table cell go in not visible to the screen.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
list = [self.listas objectAtIndex:[indexPath row]];
static NSString *CellIdentifier = #"drop";
item_drop *cell = (item_drop*) [tabela_listas dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"item_drop" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.texto_drop.text = list.nome_lista;
return cell;
}
In android i used a holder to do it. There is anything similiar on IOS?
Since you are using reusable cells of a custom subclass of UITableViewCell, make sure you register the cell identifier in the UITableView, associating it to your custom cell type. i.e:
[yourTableView registerClass:[item_drop class] forCellReuseIdentifier:#"drop"];
You typically do this when you configure subviews in the UIViewController that controls the view your UITableView is a part of, in viewDidLoad.
With that in place, you should never hit the code inside if (cell == nil).

UITextField in custom table view cell no longer brings up keyboard, iOS 7

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.

Crash with 'Could not load NIB in bundle ' while reloadRowsAtIndexPaths

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

How to add UIScrollView just in the first UITableCellView?

i have a uitableview in the uiviewcontroller, i made a scrollview in the viewload event.
i am adding it to tableview's first cell. but i scroll the tableview it displays more than one scrollview after 5 cell passed.
here is the code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"customCell";
DetailCellViewController *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nibObjects =[[NSBundle mainBundle] loadNibNamed:#"DetailCellView" owner:nil options:nil];
for (id currentObject in nibObjects)
{
if ([currentObject isKindOfClass:[DetailCellViewController class]])
{
cell = (DetailCellViewController *) currentObject;
}
}
}
if (indexPath.row==0) {
[cell.contentView addSubview:scrollView];
}
else {
NSMutableDictionary *dictionary=[catData objectAtIndex:indexPath.row-1];
NSString *title =[dictionary objectForKey:#"title"]];
[cell.catTitle setText:title];
}
return cell;
}
in which event should i add & remove scrollview?
My guess is that you're getting a dequeued UITableViewCell that already contains the UIScrollView. If you really care about separating cell types, I'd recommend setting it up so that you at least have two CellIdentifier strings. (There are times where I've set up a UITableView to handle 4+ different cell types; once you go beyond one cell type, it's pretty much just more of the same.)
My suggested solution: (see explanation below code)
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"bodyCell";
static NSString *HeaderIdentifier = #"headerCell";
UITableViewCell *cell;
// I break this up into 3 sections
// #1. Try to dequeue a cell
// #2. Create a new cell (if needed)
// #3. Set up the cell I've created
// Step 1: Try to dequeue a cell
if ([indexPath section] == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:HeaderIdentifier];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
// At this point, we may or may not have a cell to use,
// so we check for the cell's value being equal to 'nil'
// and create a new cell if it is
// Step 2: Create a new cell (if needed)
if (cell == nil) {
// Again, here we check for section to determine
// what kind of cell we want
if ([indexPath section] == 0) {
// We have the "header"/first cell
// Option 1
cell = [[ScrollViewTableViewCell alloc] init];
// Option 2 (this assumes you've got a xib named
// ScrollingTableViewCell along with a class property
// named headerCell and have properly wired it up in
// Interface Builder)
[[NSBundle mainBundle] loadNibNamed:#"ScrollingTableViewCell"
owner:self
options:nil];
cell = [self headerCell];
[self setHeaderCell:nil];
} else {
// We have a "body" cell (anything other than the first cell)
// Option 1
cell = [[BodyTableViewCell alloc] init];
// Option 2 (again, assuming you've set things up properly)
[[NSBundle mainBundle] loadNibNamed:#"BodyTableViewCell"
owner:self
options:nil];
cell = [self bodyCell];
[self setBodyCell:nil];
}
}
// At this point, whether dequeued or created
// new, 'cell' should be populated
// Again, we check for section and set up the cell as appropriate
if ([indexPath section] == 0) {
// Set up the header (UIScrollView) cell as appropriate
// This is where you would add the UISCrollView to your cell
// (if you haven't set up the UIScrollView through Interface Builder)
} else {
// Set up the "body" cell as appropriate
}
return cell;
}
NOTE: I HIGHLY recommend using Option 2 above. By far, the best results I've found when using custom/non-standard UITableViewCells is to make my own UITableViewCell subclass and xib to go along with it. Here are the steps for that:
Create a subclass of UITableViewCell (we'll call yours ScrollingTableViewCell.h/.m)
Class forward/import ScrollingTableViewCell into your UITableViewController (or UIViewController that's hosting a UITableView).
Create a class property of type ScrollingTableViewCell (we'll call yours ScrollingCell).
Create a View (New File > User Interface > View) (we'll call yours ScrollingTableViewCell.xib).
Delete the stock view item in the xib and replace it with a UITableViewCell item.
Alternative #4/5
Create an empty Xib.
Add a UITableViewCell item.
VERY IMPORTANT
In the xib, the File's Owner is the ViewController, NOT the UITableViewCell. The cell's class is ScrollingTableViewCell.
In IB, connect the ViewController's ScrollingCell property to the UITableViewCell item.
If you follow the above instructions, you should be able to allocate your cell using Option 2 above and then you can set up your cell in ScrollingTableViewCell.h/.m.

Resources