UITableViewCell Identifier without ARC floods memory - ios

I'm working on an old project that runs without ARC. It has a lot of bugs and the code looks ugly and i'm rewriting it.
Take a quick look at my code
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell = [self createCellWithInfo:[self.search objectAtIndex:indexPath.row]];
return cell;
}
-(UITableViewCell *)createCellWithInfo:(NSDictionary *)info{
UITableViewCell * cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#“Cell”] autorelease];
//set image for cell
//set text for cell.textlabel
//set text for cell.detailTextLabel
//create an UIButton and add to cell.content view
return cell;
}
the point is at this line of code
[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#“Cell”] autorelease]
if I use #"Cell" here, then the memory will rise up when I'm scrolling up and down continously on the table.
After about 15 seconds of scrolling, my iphone 5c becomes lag.
if I set it to nil, everything is fine.
Can anybody explain this please ? I'm not familliar with non-ARC.
Thanks.

Inside the if block you are creating the cell without calling autorelease, which leaks memory without ARC.
And after the if block you are recreating it anyway (whether or not it was recycled), with autorelease this time, where all you should really be doing is reset its relevant properties so that you can successfully reuse a recycled cell (or configure a new cell).
Try replacing your code as follows:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
[self updateCell:cell withInfo:[self.search objectAtIndex:indexPath.row]];
return cell;
}
-(void)updateCell:(UITableViewCell *)cell withInfo:(NSDictionary *)info{
//set image for cell
//set text for cell.textlabel
//set text for cell.detailTextLabel
//create an UIButton and add to cell.content view
}

UITableViewCell *cell = [self.table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
alone takes care of cell initialisation, you don't need the other line.

Related

UIAccessoryView not showing in sectioned table

I'm unable to display any accessories in my UITableView cells:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"Foo";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Changing the cell styles shows no difference. What's going on here?
Deleting and then creating a new file fixed the problem.
This was a result of having started with an xib file, and then deleted it in favor of doing the whole thing programmatically. Somehow, after deleting the xib, some of the delegation settings stuck.

Why is my cell nil

I am writing the code to populate a UITableView from using a CoreData database wrapped in magical record. For some reason though the code docent seem to be working and my cell is considered nil. Why is this happening?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
PassWhizEntity *pazz = [allPasses objectAtIndex:indexPath.row];
cell.textLabel.text = pazz.destinationTeacherAttribute;
//cell.detailTextLabel.text = [self.dateFormatter stringFromDate:pazz.dateAttribute];
if (cell == nil)
{
NSLog(#"cell was nil");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}
it just prints cell was nil and loads a blank UITable. Any ideas?
Your code should be like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSLog(#"cell was nil");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
PassWhizEntity *pazz = [allPasses objectAtIndex:indexPath.row];
cell.textLabel.text = pazz.destinationTeacherAttribute;
//cell.detailTextLabel.text = [self.dateFormatter stringFromDate:pazz.dateAttribute];
return cell;
}
You are trying to set textLabel of unallocated cell which have no effect on cell. Cell is returned nil because tableview don't have any cell that can be reused, so it is your responsibility to check for nil and make new Cell if needed.

Tableview subtitles on IOS7

I'm trying to add a subtitle to my tableview cells, but they are not displayed.
Where is the mistake?
Is the row
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle]
up-to-date, also with iOS 7?
Best regards
Frank
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"TestA";
cell.detailTextLabel.text = #"TestB";
return cell;
}
This code:
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
will never execute because dequeueReusableCellWithIdentifier: forIndexPath: is guaranteed to allocate a new cell.
Unfortunately, registerClass:forCellReuseIdentifier: doesn't let you specify a UITableViewCellStyle.
Change dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath to simply dequeueReusableCellWithIdentifier:CellIdentifier. This method does not guarantee a cell will be returned.* When it's not, your code will then create a new cell with the style you want.
* - (It will if you're using a storyboard, as rdelmar points out, but that's not the case here.)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
cell.textLabel.text = #"Title1";
cell.detailTextLabel.text = #"Subtitle 1";
return cell;
}
I had a similar problem and no solution on the internet worked for me. Turns out I was being an idiot. I'll post my solution just incase someone else experience a similar scenario.
I am assuming that you are using storyboard, have created a prototype and set the style to subtitle
In your storyboards document outline, make sure you select the protoptype cell and select the subtitle. See image:
Now ensure that the label font colour is of a nature that us visible on your background!
Simply subclass UITableViewCell and override
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;
with the first line being
[super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
And register your cell class with the table view
[tableView registerClass:[YourCellSubclass class] forCellReuseIdentifier:#"YourCellID"];

Static UITableViewCell backgroundView

In my project I have tableViews with static cells as well as tableViews with dynamic cells. In order to customized I've managed to get a gradient background on the cells (grouped sytle).
It works ok with dynamic TableViews as I set the background view in cellForRowAtIndex... according to the position of the row (Top, Bottom, Middle or single).
However, when I try to implement it on the static tableview cells, it doesn't work. I've tried to implement the cellForRowAtindex... but it crashes.
Does someone have an idea?
Update: the code for cellForRow..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UACellBackgroundView *bgw=[[UACellBackgroundView alloc]init];
if (indexPath.row==0) {
bgw.position = UACellBackgroundViewPositionTop;
cell.backgroundView=bgw;
}else if (indexPath.row==2){
bgw.position = UACellBackgroundViewPositionBottom;
cell.backgroundView=bgw;
}else {
bgw.position = UACellBackgroundViewPositionMiddle;
cell.backgroundView=bgw;
}
// cell.backgroundView=bgw;
return cell;
}
By the way, the Background view I got it from here: http://code.coneybeare.net/how-to-make-custom-drawn-gradient-backgrounds and here: http://pessoal.org/blog/2009/02/25/customizing-the-background-border-colors-of-a-uitableview/
if somebody is interested
It doesn't look like you are alloc the UITablViewCell, you need to alloc the cell.
For example:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// alloc the UITableViewCell
// remeber if you are not using ARC you need to autorelease this cell
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"Cell Name";
cell.detailTextLabel.text = #"Cell Detail";
return cell;
}
Add this statement:
if (cell == nil) {
// alloc the UITableViewCell
// remeber if you are not using ARC you need to autorelease this cell
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
If you have a UITableViewController subclass with a static table you should not try to dequeue cells.
Instead you should ask super for the cell. The superclass will get the cell from the storyboard and you can configure it.
Something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
UIView *selectedBackgroundView = [[UIView alloc] init];
cell.selectedBackgroundView = selectedBackgroundView;
cell.selectedBackgroundView.backgroundColor = [UIColor mb_tableViewSelectionColor];
return cell;
}
Works for all other attributes as well.

UITableViewCell initWithStyle:UITableViewCellStyleSubtitle is not working

I'm having an issue in trying to display info in a cell, one on the left and one on the right. I'm aware using initWithStyle with UITableViewCellStyleSubtitle. I use this but it doesn't seem to work.
Here is some sample code:
- (UITableViewCell *)tableView:(UITableView *)ltableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Account Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:Cellidentifier];
}
Accounts *account = [self.fetchedResultsController objectAtIndexPath];
cell.textLabel.text = account.name;
cell.detailTextLabel.text = #"Price";
return cell;
}
I can display cell.textLabel.text just fine, however I cannot get the simple "Price" to be displayed. I've tried different things, such as setting the font size of cell.detailTextLabel.
I've also tried UITableViewCellStyleValue1 as some had suggested in older posts.
Threw NSLog after setting to "Price", shows cell.detailTextLabel as null.
Not sure what I'm doing wrong.
Edit: I found this: cell.detailTextLabel.text is NULL
If I remove if (cell == nil) it works...
That check should be in place, so how do you make it work when using the different styles?
When using storyboards and prototype cells, a cell is always returned from the dequeue method (assuming a prototype with that identifier exists). This means you never get into the (cell == nil) block.
In your case the prototype cell is not defined in the storyboard with the subtitle style, so a subtitled cell is never used, and the detail text label does not exist. Change the prototype in the storyboard to have the subtitle style.
Remove all your code just once you try these lines only and check this will work or not.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier]
autorelease];
}
cell.textLabel.text=[Array objectAtIndex:indexPath.row];
cell.detailTextLabel.text=#"Price";
return cell;
}
I see the problem: in your method name, the UITableView variable is named ltableView, not tableView. Change it to tableView.
cell.detailTextLable.text should be cell.detailTextLabel.text. It looks like a simple mis-spelling of label.
All the answers mentioned here are really a workaround i.e. using storyboard.
Here is a way to do it only in code.
Basically instead of registering the identifier for the cell in viewDidLoad do it only once in cellForRowAtIndexPath: method. Also reset cell registered in viewDidLoad __sCellRegistered = 0;
static int _sCellRegistered = 0;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
if (__sCellRegistered == 0) {
__sCellRegistered = 1;
NSLog(#"register cell");
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"CellIdentifier"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"CellIdentifier"];
};
if (!cell) {
NSLog(#"dequeue");
cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
}

Resources