How to control the UITableViewCell style programmatically? - uitableview

Being working with StoryBoard I have this situation, with the code below:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text=[[cityArray objectAtIndex:indexPath.row] valueForKey:#"CELL_TEXT"];
cell.detailTextLabel.text=[[cityArray objectAtIndex:indexPath.row] valueForKey:#"DETAIL_TEXT"];
My tests show me that regardless of the fact that I use UITableViewCellStyleDefault, or UITableViewCellStyleSubtitle when performing the alloc, the two last lines of code above will work.
Those two last lines are only depending on my settings in the StoryBoard (cell style to Subtitle or not).
Now here is my question: How can I programmaticaly control the style of the cells, going from UITableViewCellStyleDefault to UITableViewCellStyleSubtitle and vice versa?
Obviously, changing the alloc only, does not work; and I did not find any property that I could set either.

If you're using a Storyboard with a prototype cell, the cell will not be nil. It will always be created. Either don't use a prototype cell in a Storyboard or allocate a different protoype cell from the Storyboard.

Related

DetailTextLabel behaving strangely

I am trying to set the subtitle label on a UITableViewCell. I have a dictionary containing the pairs of titles and subtitles and the list of keys is stored in self.results. However when I run with the following code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Search Result Cell" forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Search Result Cell"];
}
cell.textLabel.text = [self.results objectAtIndex:indexPath.row];
cell.detailTextLabel.text = self.resultPairs[[self.results objectAtIndex:indexPath.row]];
NSLog(#"%#", self.resultPairs[cell.textLabel.text]);
The subtitle remains blank, but the NSLog prints the correct output. What is going on here? When I set the detailTextLabel to a constant it works fine.
The problem is that the default cell style does not include a subtitle. If you are using a storyboard, you just need to set the style to Subtitle in Interface Builder.
The solution turned out to be that the strings contained allot of initial whitespace, resulting in them being padded out of the view.

create UITableViewCell programmatically

I am trying to create a UITableViewCell that contains a UIScrollView that is able to scroll horizontally for each cell in the UITableView.
Everything shows correctly and works well. However, when I scroll constantly up and down on the UITableView, memory usage goes up and up and up and up..... which I think means that I am constantly adding the custom elements over each over when the UITableViewCell is being reused. I would like to know how I can stop this from happening.
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Configure the cell...
NSDictionary *cellDictionary = [xmlMArray objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// code
codeString = [[UILabel alloc] initWithFrame:CGRectMake(15.0, 0.5, 70.0, 40.0)];
codeString.text = [cellDictionary objectForKey:#"Code"];
codeString.backgroundColor = [UIColor clearColor];
// series
addressString = [[UILabel alloc] initWithFrame:CGRectMake(220.0, 10.5, addressString.frame.size.width, 50.0)];
addressString.text = [NSString stringWithFormat:#"PC %#: %#",[cellDictionary objectForKey:#"Number"] ,[cellDictionary objectForKey:#"Street"]];
[addressString sizeToFit]; // Dynamic UILabel width
addressString.backgroundColor = [UIColor clearColor];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIScrollView *scrollCell = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.frame.size.width, cell.frame.size.height)];
[scrollCell setContentSize:(CGSizeMake((220.0 + addressString.frame.size.width)+15, cell.frame.size.height))];
[scrollCell addSubview:codeString];
[scrollCell addSubview:addressString];
[cell addSubview:scrollCell];
return cell;
}
There seems to be two problems here. I'll try to explain what's actually happening, but you should follow mbm29414's answer on what to do.
In the first part of this method, you are asking for a UITableViewCell using the identifier:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
The next part is to check if you received a cell with this call:
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
This means that if your first line of code DID NOT return a cell-object, then you are instantiating a new one.
Later on in your method, you are instantiating yet another cell:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
UIScrollView *scrollCell (...)
This way you might not actually be reusing the cells, I'm not sure. At the very least, it should not be there. You potentionally allocate double the space each time.
Remove the last instantiation, and that should probably help a little.
The other problem, I think, is that you're adding scrollView and UILabels to your cells' subviews. Your circle of life:
Create cell
Create 2 UILabels
Create ScrollView
Add labels to ScrollView's subview
Add scrollView to Cell's subview
Send cell on it's merry way
When your cell is brought back from the dead during [tableView dequeueReusable..], they still contain the UIScrollView with the UILabel. Your code does not take advantage of that, but rather ignores it. This means that you are adding an ADDITIONAL scrollView with labels into your cell. If you scroll up and down a lot, this means that one single cell can possibly contain 50 different scrollViews, all of them taking the same amount of processing.
This is what happens next:
Get cell from the queue
(this cell already contains UIScollView and UILabels)
Add new scrollView with labels anyway
Send it on it's merry way (now with 2 scrollViews and 4 labels)
To solve this, you should do as mbm29414 suggested, to make your own subclass of UITableViewCell. That way, you can say cell.codeString.text=#"blah";
While you are re-creating a new UITableViewCell each time, you also appear to be endlessly adding UIScrollView and UILabel objects.
First, remove the second call of:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
Second, try subclassing UITableViewCell, making the UI like you like it either in an init method or in IB. Then, make a "setup" method that takes an object and configures each UI element accordingly. That way, you can not only recycle your cells, but also keep from continually creating more UIView subclass instances.
Couple of things.
Your check to see if the table view cell returned by
dequeueReusableCellWithIdentifier: is nil is not necessary, because
that method won't return nil anymore unless you've made a mistake with your identifier. It used to (I think before iOS
6).
Later in the code you're creating a new cell and assigning it to the cell variable which is eventually returned. Why? You already created one, so creating a second is fundamentally wrong.

UITableViewCells reverting back to default or other values

So I've created a TableView as below, but I have quite an annoying problem.
When I come to this VC, I click Choose User, and I selected user Atoshum.
When I scroll down, this top cell goes off screen as I scroll through the bottom cells.
When I scroll back up, the cell has reverted to a default (or occasionally, takes the value of another cell).
I make the cells as such.
static NSString *CellIdentifier = #"Cell";
DMSDrugInstanceCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!Cell) {
Cell = [[DMSDrugInstanceCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Cell.chooseUserButton.tag = indexPath.row;
[Cell.chooseUserButton addTarget:self
action:#selector(performSegue:)
forControlEvents:UIControlEventTouchUpInside];
return Cell;
In the cell creation you dont ever set any values. All you do is set the tag and then add an event target. If you want it to keep the choose, you need to store/save that choice when it is made and then in the cell create, set it based on that saved value.
you are reusing table cell. So every time your cell reload then you need to set value in cell.
in cellForRowAtIndexPath method , you need to set value in cell according to index path.
This is because the UITableView do not create the new cells for total number of elements. Rather it re-uses the cells which are off the visibility. Hence you feel that your data is reset or getting reflected on some other cell.
The best approach is to store all your data in some Array (let it be tagDataArray) and then set your cells as
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
DMSDrugInstanceCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[DMSDrugInstanceCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Cell.chooseUserButton.tag = [tagDataArray objectAtIndex:indexPath.row];
...
...
return Cell;
}

Register UITableViewCell with a UITableViewCellStyle

I know i can register a class or NIB file as a UITableViewCell. But I want to do the iOS 6 way of
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
How could I achieve this (specifying the cell style) while still using registerClass:ForReuseIdentifier:
If you use register class or register nib, then you don't use the if(! cell) clause at all, and you should use dequeueReusableCellWithIdentifier:forIndexPath: instead of the one you're using. You will get whatever style you created in your nib or class. Usually, that wouldn't be any of the Apple default styles, it would be your own custom style.
If you just want one of Apple's predefined styles, then the easiest way is to choose that style in IB and give it a reuse identifier -- in that circumstance, you should register anything, the system will automatically get the cell from the storyboard.

UITableView Controller with prototype custom cell and search display controller tableview

is there a way I can have in the search results controller table view the exact same styling (height, background etc) I have in the prototype cell of my tableview controller in iOS5?
The root view has a background picture and a specific cell height. The search table does not appear with the background picture and the cell height is lower;
Another way is to just use the same cell identifier (at least if you're using storyboards), so for example:
static NSString *CellIdentifier = #"searchCell";
myCustomCell *cell = (myCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//for search controller need to check if cell is nil, if it is create one since there won't be any to reuse to begin with
if (!cell) {
cell = (myCustomCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
Other properties such as row heights etc can be set by accessing properties of
self.searchDisplayController.searchResultsTableView

Resources