How to prfioritize the tableView cells in order to display at the top of tableView in the mothod cellForRowAtIndexPath?
I want to display the priority cells at the top of the tableView cells checking if they have priority or not, depending on the bool value of havePriority property, such that if havePriority is 1, it should be true else should be after the priority list.
I've tried by using different cell identifiers but unable to got the list at the top.
My Code:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (havePriority) // if the cell wants priority to be at top, have a value in bool
{
cell.textLabel = sOmeText; //
NSLog(#"%#",sOmeText);
}
return cell;
You shouldn't be setting the order of the cells in that method. By then it is far too late.
This is really something that should be done in the model layer. The list of items to be displayed should already be sorted according to their priority, and that way they will show up at the top.
Secondarily, this type of code isn't really necessary anymore:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
You should be using the more modern method:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
This will either return a cell from the reuse pool or create a new one, so it always returns a cell, and there is no need to create one yourself.
Related
Hi I have this problem that if I add more than 13 items in my uitableview the items will repeat
this is my code for
Adding:
[categoryList insertObject:inputcategory atIndex:0];
NSIndexPath *indexpath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtindexPaths#[indexpath] withRowAnimation:UITableViewRowAnimationAutomatic];
CellForRow:
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.textlabel.text = [categoryList objectAtIndex:indexPath.row];
}
NumberofRows
return [categoryList count];
the first 12 items are okay but after that it adds the same last object in my NSMutableArray again in my uitableview and when I reload it, It only records 12 items.
In cellForRowAtIndexPath: method change
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.textlabel.text = [categoryList objectAtIndex:indexPath.row];
}
to
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textlabel.text = [categoryList objectAtIndex:indexPath.row];
If you set text in if (cell == nil) it will not updated on reusing the cell. When reusing the cell will not be nil.
Akhilrajtr's answer is correct but is the old way of doing it. In 2014 for iOS 6+ you should instead be using the UITableView methods
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier
or
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier
and
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath
Getting a cell in cellForRowAtIndexPath: becomes much simpler...
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
"identifier" is the unique string used to identify cells for reuse, just like the old way.
From Apple's documentation, "This method dequeues an existing cell if one is available or creates a new one based on the class or nib file you previously registered." You don't need to use initWithStyle any more, and if you think you do then consider subclassing UITableViewCell instead to more precisely control the appearance of your cells.
No more checks for the cell being nil are required. Just go ahead and set labels if your cell is a plain UITableViewCell or configure your subclassed cell (which should of course have made itself ready for reuse with the prepareForReuse: method)
Apple mention the performance this in their documentation on UITableViews.
it's should be about Reuse Cells. So if the cell != nil u can't got this below work:
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.textlabel.text = [categoryList objectAtIndex:indexPath.row];
}
Reuse cells. - Object allocation has a performance cost, especially if the allocation has to happen repeatedly over a short period—say, when the user scrolls a table view. If you reuse cells instead of allocating new ones, you greatly enhance table view performance.
I have added a UILabel as the content view of my tableview. The text in the UILabel is overlapping upon scrolling. Below is the code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.chatTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Group"];
static NSString *CellIdentifier = #"Group";
UITableViewCell *cell = [self.chatTableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = self.latestTrimText;
UILabel *cellLabel = [[UILabel alloc]init];
cellLabel.text = self.dateOfLatestTrim;
cellLabel.frame = CGRectMake(15, 0, 150, 30);
[cell.contentView addSubview:cellLabel];
return cell;
}
I can fix this by changing to UITableViewCell *cell = [self.chatTableView dequeueReusableCellWithIdentifier:nil];
But then, the scrolling of the tableview won't be smooth. Is there another way to fix the issue?
The tableview cells are recycled and reused potentially an infinite amount of times. This is what the reuse identifier stands for.
Take care not to add any subview outside the if (cell==nil) block. Now you are just adding again and again a new label to the same cell instance. This is why your texts overlaps each other.
I would recommend you to read the documentation on how the cells are recycled and reused.
Your fix is not correct because by passing a nil reuse id, you are just preventing the recycling process to play. You create a new instance for each row of your tableview. This is why you have performance issues then.
So I register my cell:
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// setting up the cell
}
The issue is I can't set the cell.detailTextLabel.text property. The cell is never nil.
If called first, table view registerClass will cause dequeueReusableCellWithIdentifier to return non-nil cell if the cell reuse identifier matches.
I believe registerClass is generally used for cells that will be a custom cell derived from UITableViewCell. Your custom cell can overrite initWithStyle and set the style there.
It's not always necessary to create a custom cell.
If you want to set the cell style then don't call registerClass.
you need do followed 3 changes to achieve you goal:
remove registerClass statement.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
=> UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
use initWithStyle:UITableViewCellStyleSubtitle
usually there are two ways to create cell with subtile, firstly with custom UITableViewCell, set style in the init. secondly with followed code, which is what you wanted:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
The easiest way is to use the storyboard, and set the cell style in IB. In that case, you shouldn't register anything, nor should you have an if (cell == nil) clause. It doesn't seem to matter whether you use dequeueReusableCellWithIdentifier: or dequeueReusableCellWithIdentifier:forIndexPath. They both are guaranteed to return a cell when that cell is created in the storyboard.
Create a custom cell. Change its style in interface builder. Use table view register the cell from nib your view controller.
And the code:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"YourCustomCell" bundle:nil] forCellReuseIdentifier:kReuseIdentifier];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
YourCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:kReuseIdentifier];
// Do things with the cell.
// The cell has no chance to be nil because you've already registered it in viewDidLoad method.
// So there's not need to write any code like if(cell==nil).
// Just use it.
return cell;
}
Try using the UITableViewCellStyleSubtitle style for the cell. Change the line in the if statement to this:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
You need to change the cell style:
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
to this
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
This will work for you.
This is an old question. I just want to provide a alternative solution.
Why not try below, after you register the cell:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
then do:
[cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier ];
It works for me.
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];
}
I have a problem with implementing AdMob in my UITableView. I have an array (newsItems) that contains news-feeds from different websites. The array is sorted by the date of the newsitem. I want to display the newsitems in a tableview, but in the free version of the app I want an advertisement from AdMob to show in every 10th tableviewcell.
I used the code from an other answer to add the ads to the tableview:
if (0 == (row % 10)) {
//cells with an add
static NSString *MyIdentifier;
NSInteger row = [indexPath row];
MyIdentifier = [NSString stringWithFormat:#"AdCell%d", row];
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
[cell.contentView addSubview:[AdMobView requestAdWithDelegate:self]];
return cell;
} else {
// the code to create a standard cell (simplified)
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
NSString *cellValue = [newsItems objectAtIndex:indexPath.row];
cell.text = cellValue;
}
I know this is not correct. By using “[newsItems objectAtIndex:indexPath.row]” the table is populated by going through the array and adding the newsitem at the index to the matching row. This means that if an add should be added to row 10, the corresponding newsItem at row 10 of the array is not ignored and overwritten by the AdWhirl-ad.
In stead I want that newsitem to be added to the row beneath the ad. Is this possible?
I had a ListObject class which would store the data about that cell (eg. Title, thumbnail, desc etc.) so I added a field: BOOL isAd and then just added a new ListObject with isAd = YES every 10 objects and made sure that my cell creation and height logic knew what to do with Ad cells. This way, you have a list data object for each Ad view in your table.