Using alloc and init when using a UITableViewCell from Storyboard - ios

I'm doing a simples app using Storyboard that a have a View with a UITableView with a UITableViewCell that do the navigation to another UIView.
So a have to code to populate the cell on the table view.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"SampleCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
NSLog(#"cai no init da cell");
}
GPItem *item = [self.items objectAtIndex:indexPath.row];
cell.textLabel.text = #"Post";
cell.detailTextLabel.text = item.imageURL;
return cell;
}
I realised that the code if (cell == nil) { ... never executes so I really need to do that on uses the cell from Storyboard?
Thanks.

You are correct; that code is guaranteed to return a non-nil cell if you are using a storyboard. Also, in iOS 6, the new call dequeueReusableCellWithIdentifier:forIndexPath: never returns nil. See the discussion in my book:
http://www.apeth.com/iOSBook/ch21.html#_registering_a_cell_class

If you've declared your UITableViewCell in table view's prototype cells it's already allocated and just needs to be dequeued. If you're using a custom UITableViewCell subclass, then you must check if it's nil and allocate new entities when necessary.

Nope you don't need that code when using a cell made in your storyboard.
It is probably best to remove this code so that you crash nice and early if the identifier you gave to the cell in interface builder and the identifier you use in code ever drift. This snippet will mask this error and just provide a cell that you most likely was not intending to have.

Related

Custom prototype cell in UIStoryboard is created but doesn't show up in UITableView

I have a project where I need to use a custom UITableViewCell. I'm designing the cell as a prototype in storyboard and it looks fine there. I assign the prototype to my custom UITableViewCell subclass, give it the same reuse identifier I'm using in my UITableView and link the UILabel on the prototype cell to an IBOutlet in my UITableViewCell subclass.
When I call it from the UITableView the cell is created and if I add labels and buttons in the code of that class (create them with a CGRect and all) they all work but the labels I've added in the storyboard never show up.
I don't understand how my subclass can be called and created successfully but its layout and subviews from the storyboard don't seem to exist as far as my app is concerned. What am I doing wrong?
Here's my cellForRowAtIndexPath code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
// Configure the cell...
return cell;
}
I've run into this issue before, and in my case, the problem was that the auto-generated code for the view controller included a call to:
[UITableView registerClass:forCellReuseIdentifier:]
I would suggest checking for and removing any calls to the above, or to
[UITableView registerNib:forCellReuseIdentifier:]
and trying your original code again.
acreichman, add casting in cellForRow and put an NSLog in you cell's awakeFromNib to see if you get there. Let me know...
Your cellForIndexViewPath should look like this, to create a simple custom cell with label,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
Make sure that you have made all connections well, set datasource and delegate to table and then set the “Identifier” of the custom cell to "MyTableViewCell" in “Attributes Inspector” like this,
For storyboard:
Add "MyTableViewCell" instead of "SimpleTableCell" as shown in above screenshot.

List Songs in UITableViewController on iPhone? Works in Storyboard, NOT without it

I am NOT using Storyboards. I have a UITableViewController and I would like to display a list of songs from user's library.
This is my code so far:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
NSArray *songs = [songsQuery items];
return [songs count];
}
But for this block, I do not know what to do. I found a tutorial for storyboards, but it is not valid here:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
NSArray *songs = [songsQuery items];
MPMediaItem *rowItem = [songs objectAtIndex:indexPath.row];
cell.textLabel.text = [rowItem valueForProperty:MPMediaItemPropertyTitle];
cell.detailTextLabel.text = [rowItem valueForProperty:MPMediaItemPropertyArtist];
return cell;
}
This only works in Storyboard because I can click the cell in the storyboard and rename its identifier to 'Cell'. In the .xib/nib file in my project, all I see is a view filled with country's names. I cannot click a single cell, I can only edit the whole table.
My question is, what code must I put in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath in order to display this list?
Thanks!
The basic problem you're encountering is that, when used in conjunction with a properly configured storyboard, dequeueReusableCell... will create a cell of the appropriate type if none is available to dequeue.
If you are using a standard UITableViewCell, you can use the following block to dequeue and/or create an appropriate cell:
static NSString* reuseIdentifier = #"Cell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
}
If, on the other hand, you're loading your cells from a nib file, you can just add:
[self.tableView registerNib:[UINib nibWithNibName:nibName bundle:[NSBundle mainBundle]] reuseIdentifier:reuseIdentifier];
to your viewDidLoad.
Alternatively you can use registerClass:forCellReuseIdentifier: if you have a custom cell class that sets up it's own subviews.
First off, check if the cell being dequeued is nil or not.
The next thing I can see a problem with is the fact that you aren't really loading anything in cellForRowAtIndexPath:. Basically what this method does is dequeue some cell which has been marked for reuse in an attempt to save memory, and if you haven't set the proper Restoration Identifier in the Interface Builder, then there is no way to know which Nib you want initialized to use here.
What used to happen (or at least my understanding of it) is that in cellForRowAtIndexPath: you would have to check if the cell returned from dequeueReusableCellWithIdentifier: was nil, and if so, you'd have to create the cell from scratch using something like this:
SomeCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[[NSBundle mainBundle] loadNibNamed:#"SomeCellNib" owner:self options:nil] objectAtIndex:0];
}
and this would ensure that if no cell was dequeued that you would load up a fresh one from scratch, although I believe that Apple actually changed how dequeueReusableCellWithIdentifier: works, and as long as you've registered the Identifier, it will create a new cell for you.
For this reason I'm not sure what the problem is if you've set the Identifier properly, and all I can suggest is to try and manually load the cell.
EDIT: I forgot to mention where Restoration Identifiers can be set. The Restoration Identifer field is in the Identity tab, or the third tab in the Interface Builder:
To create a prototype cell inside a .nib, drag a UITableCellView out from the right sidebar. From there you can create your cell prototype, as well as set the cell reuse identifier.

DisclosureButton Indicator or Any kind of Accessory Type doesn't seem to appear when set on a UiTableViewCell

This is a weird thing I have been noticing lately. I am not able to see the accessory Type for my UITableView Cell even after setting the accessoryType with the following code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"LocationCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: CellIdentifier] autorelease];
}
if (indexPath.section == 0) {
cell.textLabel.text = #"Move to a New Location";
}else{
cell.textLabel.text = [self.locArray objectAtIndex:indexPath.row];
}
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
It doesn't matter what accessory type I set. It always displays just the text label in the cell but, no button. Am I missing something? Note that this is not the first time I am using a UITableViewCell. I have never come across this problem earlier. Meanwhile I am testing this on iOS6 and have confirmed this behavior both on the iPad simulator as well as the device it self.
Well! I have solved this. My Viewcontroller was initially a subClass of UIViewController instead of UITableViewController. I did this thinking I would be adding extra views to the main View which would have nothing to do with the TableView. I then changed it to UITableViewController and voila it all worked perfect. But then this is a trade off between the flexibility provided by UiViewController and UitableViewController as I now have to add those extra views either in to the headerview or the footerview of the TableView. Nonetheless I have to deal with it any way. I hope this would help some one.

dequeueReusableCellWithIdentifier does not work

I want to load around 6000 - 8000 rows in a UITableview. I get the data from the server using a async call and when I get the data I call
[tableView reloadData]
This is to refresh the table view . But because of some reason my app gets stuck and freezes .
When I debug , I found that cellforrowatindexpath is called 6000 times (on main thread) and
dequeueReusableCellWithIdentifier always returns null .
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CDTableRowCell *cell = nil;
// Create and Resue Custom ViewCell
static NSString *CellIdentifier = #"CellIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// got into render/theme objec
if(cell == nil){
cell = [[CDTableRowCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// MODIFYING CELL PROPERTIES HERE FROM AN ARRAY
// NO HTTP CALLS
}
Also, tableview starts reusing cell once I start scrolling but before that I never always create a new one.
Any clue why this strange behavior ???
try like this,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier =#"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
return cell;
}
The method in your question is not a table view datasource method. The datasource method has the table view as an argument. The method you have written is one that can be used to obtain a cell from the tableView itself, not to obtain a new cell from the datasource.
I don't know how often that method is called but overriding it is almost certainly not what you want to do.
I'm guessing you have subclassed a uitableview to be its own datasource? If so, you need to have the code in your question in the datasource method tableView:cellForRowAtIndexPath:, and not override the method as you have now.

Warning in table view

I'm using the table view in the view controller, with the simple array was displayed in the list. That array was displays and works fine but I'm getting this warning. May I know the reason for this and please some ideas to rectify this issues..
WARNING: Using legacy cell layout due to delegate implementation of
tableView:accessoryTypeForRowWithIndexPath: in . Please remove your implementation of this method and set
the cell properties accessoryType and/or editingAccessoryType to move
to the new cell layout behavior. This method will no longer be called
in a future release.
Thanks
The method tableView:accessoryTypeForRowWithIndexPath: is deprecated in iPhone OS 3.0. Delete the implementation of this method and add the following code in the method cellForRowAtIndexPath: :
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
See UITableViewCellAccessoryType in the documentation for other type.
Im using the following code as you mentioned :
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
cell.text = [arry objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
But it returns the same
Its just saying that this method is about to disappear in next version, so you should go to documentations look for tableView:accessoryTypeForRowWithIndexPath and surely you will find alternative ways of doing what you want you want to do.
In other words, set the accessory of that cell by calling UITableViewCell accessory-view and accessory-type properties
myCell.accessoryType = ...
myCell.accessoryView = ...

Resources