I'm trying to set the title and display a button in my custom cell object in my second table view controller, but only my first dynamic prototype cell is displaying text.
The first prototype cell is UITableViewCell and the second is the custom object. In my first view controller I implement almost the same exact method and it works completely fine. Not sure where my error could be, the models I use have all their data in them. I have the correct cell identifier in my storyboard, and the connection from custom cell to the UIButton is set.
Thanks in advance.
Method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
static NSString *QuestionSectionIdentifier = #"QuestionSectionCell";
if (indexPath.section == 0)
{
UITableViewCell *cellQuestion = [tableView
dequeueReusableCellWithIdentifier:QuestionSectionIdentifier];
if (cellQuestion == nil) {
cellQuestion = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:QuestionSectionIdentifier];
}
if (indexPath.row == 0) {
cellQuestion.textLabel.text = _headerQuestion.question;
NSLog(#"question here %#", cellQuestion.textLabel.text);
}
return cellQuestion;
}
else
{
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if (indexPath.section == 1)
{
if (indexPath.row == 0)
{
[cell.firstButton setTitle:_headerQuestion.questionAuthor.fullName forState:UIControlStateNormal];
[cell.firstButton setTag:_headerQuestion.questionAuthor.userID];
[cell.answerLabelField setHidden:YES];
NSLog(#"section 1 %#", cell.firstButton.titleLabel.text);
}
}
else if (indexPath.section == 2)
{
Answer* answer_num = [_headerQuestion.answers objectAtIndex:indexPath.row]; //object at index
[cell.firstButton setTitle:answer_num.answerAuthor.fullName forState:UIControlStateNormal];
[cell.firstButton setTag:answer_num.answerAuthor.userID];
cell.answerLabelField.text = answer_num.answer;
}
return cell;
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 3;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0)
{
return 1;
}
if (section == 1)
{
return 1;
}
else
{
return [_headerQuestion.answers count];
}
}
Make sure you register both reuse identifiers with the tableview using
- (void)registerClass:(Class nullable)cellClass
forCellReuseIdentifier:(NSString * nonnull)identifier
Or registerNib if you have a nib for the cell.
Related
I have a tableView with a custom cell. I have the posibility to save to favorites some of the elements , and when this is happening i want to add a star image in cell. I was trying doing this , but after the star appears, i have a problem . I think it's because of reusable cell but i dont know how to solve it . My problem is : stars appear again on the other cells even if the word is not added on favorites.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
dictionaryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell=[[dictionaryTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
if (tableView == self.searchDisplayController.searchResultsTableView)
{
cell.textLabel.text = [self.searchResult objectAtIndex:indexPath.row];
}
else
{
cell.word.text = self.tableData[indexPath.row];
BOOL isTheObjectThere = [self.favoriteArry containsObject:self.tableData[indexPath.row]];
if (isTheObjectThere==TRUE) {
cell.favImg.image=[UIImage imageNamed:#"3081#3x.png"];
}
}
return cell;
}
Replace following code in place of cellForRowAtIndexPath. you will get your desire output.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
dictionaryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell=[[dictionaryTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
cell.favImg.hidden = YES;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
cell.textLabel.text = [self.searchResult objectAtIndex:indexPath.row];
}
else
{
cell.word.text = self.tableData[indexPath.row];
BOOL isTheObjectThere = [self.favoriteArry containsObject:self.tableData[indexPath.row]];
if (isTheObjectThere==TRUE) {
cell.favImg.hidden = NO;
cell.favImg.image=[UIImage imageNamed:#"3081#3x.png"];
}
}
return cell;
}
Hope this help you.
You have to remove the image if the object is not TRUE
if (isTheObjectThere==TRUE) {
cell.favImg.image=[UIImage imageNamed:#"3081#3x.png"];
} else {
cell.favImg.image=nil;
}
Yes, you are right it's because of reusing your cells via dequeueReusableCell with identifier as-
dictionaryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
according to your requirements you set a star image on a cell to indicate some favorite elements on the respective cell, like this
BOOL isTheObjectThere = [self.favoriteArry containsObject:self.tableData[indexPath.row]];
if (isTheObjectThere==TRUE) {
cell.favImg.image=[UIImage imageNamed:#"3081#3x.png"];
}
When any cell with star image is reused than it should be removed if the next cell does not some favorite elements but if it does have some favorite elements than it should be used as-
To resolve this issue just add the else case with the above if statement as
if (isTheObjectThere == TRUE)
cell.favImg.image=[UIImage imageNamed:#"3081#3x.png"];
else
cell.favImg.image=nil;
This question already has answers here:
UITableView: Handle cell selection in a mixed cell table view static and dynamic cells
(6 answers)
Closed 7 years ago.
I'm using a UITableView to show sth,and the information in section 1,section 2 will not change,but section 3 is dynamic.
Is there any way to show section 1&2 using static cell,but I can write the datasource of section3?
Here you will get as per your requirement.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0 || section == 1) {
return 1; //However many static cells you want
} else {
return [_yourArray count];
}
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
if (indexPath.section == 0 || indexPath.section == 1 ) {
NSString *cellIdentifier = #"staticCellType";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = #"some static content";
return cell;
} else if (indexPath.section == 1){
NSString *cellIdentifier = #"dynamicCellType";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [_yourArray objectAtIndex:indexPath.row];
return cell;
}
return nil;
}
You can easily do like this....
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3; //number of section
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch(section){
case 0:
return 1; //static value as per your requirement
break;
case 1:
return 1; //static value as per your requirement
break;
case 2:
return [yourArray count]; //static value as per your requirement
break;
default
return 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CELL";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (indexPath.section == 2) {
NSDictionary *dict = [yourArray objectAtIndex:indexPath.row];
}
//If you perform any task for other section then you can write in switch case
return cell;
}
Can I achieve this?
if (indexpath.section == 0) {
// Use Class 1
} else if (indexpath.section == 1) {
// Use Class 2
}
I tried this but not working
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
OneTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"One" forIndexPath:indexPath];
if( cell == nil){
cell = [[OneTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"One"];
}
cell.oneLabel.text = #"HAHAHA";
return cell;
}else{
TwoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Two" forIndexPath:indexPath];
if( cell == nil){
cell = [[TwoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Two"];
}
cell.twoLabel.text = #"HEHEHE";
return cell;
}
}
From the code that you show, your oneLabel and twoLabel are never initialized. If you want a quick fix, you can replace both of them with textLabel. Something as the following,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
OneTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"One" forIndexPath:indexPath];
if( cell == nil){
cell = [[OneTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"One"];
}
cell.textLabel.text = #"HAHAHA"; // Modified
return cell;
} else {
TwoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Two" forIndexPath:indexPath];
if( cell == nil){
cell = [[TwoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Two"];
}
cell.textLabel.text = #"HEHEHE"; // Modified
}
}
And you will be able to see different text for two different sections in the table view. And they are indeed different TableviewCell classes.
However, if you want to use different labels for different UITableViewCell, then you have to make sure that they are initialized somehow somewhere. For example, you could overwrite the default UITableviewCell initializer in your custom table view cell. For example, in your OneTableViewCell.m file, add the following between #implementation and #end. In this case, you can use your original code in the UITableView class.
#implementation OneTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if ( self ) {
_oneLabel = [[UILabel alloc] init];
[self.view addSubView:self.oneLabel];
}
return self;
}
#end
I have 2 tableViews, the first only loads a list from an array.
The other 1, show details per row. But it shows a crash report:
'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath: Exception'
What seems to be wrong with my code? I want to show each row a different detail that came from the same sqlite row.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
//tableView 1
if(tableView == self.cTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"courseCell"];
NSLog(#"Here.");
Course *courses = [self.course objectAtIndex:indexPath.row];
cell.textLabel.text =courses.cName;
cell.detailTextLabel.text =courses.cSchool;
return cell;
}
//tableView 2
if(tableView == self.jTableLabel)
{
if (indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"JobName"];
cell.textLabel.text = _jDetails.jName;
}
else if (indexPath.row == 1)
{
cell= [tableView dequeueReusableCellWithIdentifier:#"JobEarnings"];
cell.textLabel.text = #"Job Earnings (per month): Php";
cell.detailTextLabel.text = _jDetails.jEarnings;
}
return cell;
}
return 0;
}
For performance reasons, a table view's data source should generally reuse UITableViewCell objects when it assigns cells to rows in its tableView:cellForRowAtIndexPath: method. A table view maintains a queue or list of UITableViewCell objects that the data source has marked for reuse. Call this method from your data source object when asked to provide a new cell for the table view. This method dequeues an existing cell if one is available or creates a new one using the class or nib file you previously registered. If no cell is available for reuse and you did not register a class or nib file, this method returns nil.
If you registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method. For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.
You need to create different cells for each tableview, Try to use the above code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
//tableView 1
if(tableView == self.cTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
else
{
for(UIView *view in cell.contentView.subviews)
{
[view removeFromSuperview];
}
}
NSLog(#"Here.");
Course *courses = [self.course objectAtIndex:indexPath.row];
cell.textLabel.text =courses.cName;
cell.detailTextLabel.text =courses.cSchool;
return cell;
}
//tableView 2
if(tableView == self.jTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
else
{
for(UIView *view in cell.contentView.subviews)
{
[view removeFromSuperview];
}
}
if (indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"JobName"];
cell.textLabel.text = _jDetails.jName;
}
else if (indexPath.row == 1)
{
cell= [tableView dequeueReusableCellWithIdentifier:#"JobEarnings"];
cell.textLabel.text = #"Job Earnings (per month): Php";
cell.detailTextLabel.text = _jDetails.jEarnings;
}
return cell;
}
return 0;
}
Please cross check either one of your table is returning more number of rows in numberOfRowsInSection method . It might be that you haven't put check on this method as both of the table are returning different number of rows .
First, check that your numberOfRowsInSection returns the correct number of rows for your table. I would think this would be it.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(tableView == self.cTableLabel)
{
return [self.course count];
}
//tableView 2
if(tableView == self.jTableLabel)
{
return 2;
}
return 0;
}
Otherwise I would set a break point on return 0; or NSLog before it in cellForRowAtIndexPath, because my guess is neither if block is hit and you are returning zero. Does it get triggered?
Edit - Ah, I think I see dequeueReusableCellWithIdentifier: will return a nil cell if you haven't set one up yet. Try using dequeueReusableCellWithIdentifier: forIndexPath: instead. This will always return a valid cell assuming you called registerClass:[UITableViewCell class] forCellReuseIdentifier: first.
Give this a shot:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"courseCell"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"JobName"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"JobEarnings"];
//tableView 1
if(tableView == self.cTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"courseCell" forIndexPath:indexPath];
NSLog(#"Here.");
Course *courses = [self.course objectAtIndex:indexPath.row];
cell.textLabel.text =courses.cName;
cell.detailTextLabel.text =courses.cSchool;
return cell;
}
//tableView 2
if(tableView == self.jTableLabel)
{
if (indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"JobName" forIndexPath:indexPath];
cell.textLabel.text = _jDetails.jName;
}
else if (indexPath.row == 1)
{
cell= [tableView dequeueReusableCellWithIdentifier:#"JobEarnings" forIndexPath:indexPath];
cell.textLabel.text = #"Job Earnings (per month): Php";
cell.detailTextLabel.text = _jDetails.jEarnings;
}
return cell;
}
return 0;
}
Also registerClass:[UITableViewCell class] forCellReuseIdentifier: could be called in your init, it only needs to be declared once.
I am using tableview apple's lazy loading code in my project,but having exception in project. And error is - *** Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:],here is my code please help.But it is working in other project.I have no delegate method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"LazyTableCell";
static NSString *PlaceholderCellIdentifier = #"PlaceholderCell";
NSUInteger nodeCount = [self.entries count];
if (nodeCount == 0 && indexPath.row == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
cell.detailTextLabel.text = #"Loading…";
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nodeCount > 0)
{
AppRecord *appRecord = [self.entries objectAtIndex:indexPath.row];
cell.textLabel.text = appRecord.name;
if (!appRecord.appIcon)
{
if (self.mytable_view.dragging == NO && self.mytable_view.decelerating == NO)
{
[self startIconDownload:appRecord forIndexPath:indexPath];
}
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
else
{
cell.imageView.image = appRecord.appIcon;
}
}
return cell;
}
Because cellForRowAtIndexPath is returning a nil value and then configureCellForDisplay is expecting a UITableViewCell. The storyboard or XIB does not have a cell defined with the cell identifier you specified. Better check the spelling of identifier.
Please check for Delegate.
Have you added both delegate or not?
UITableViewDelegate, UITableViewDataSource
import UIKit
class UserFriendVC: UIViewController, UITableViewDelegate, UITableViewDataSource
{
override func viewDidLoad() {
super.viewDidLoad()
}
}
you should add cellIdentifier from "Show the attributes inspector". Please fallow just like below snippet.
Firstly added below code to your-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath delagate method.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ResultCustomTableViewCell *cell = (ResultCustomTableViewCell *)[resultTableView dequeueReusableCellWithIdentifier:#"ResultTableViewCellIdentifier"];
...
//set the cell property
...
return cell;
}
and then jump the "Show the attributes inspector", While selected cell root view.
And then paste the same identifier name to identifier section in "Show the attributes inspector". in this case i use this ResultTableViewCellIdentifier.
And one more think. if you use custom cell just like this scenario, you must add below delegate metod. Because your custom cell height can be higher or smaller original tableview height. And Also you should register this nib in viewDidLoad.
- (void)viewDidLoad {
[resultTableView registerNib:[UINib nibWithNibName:#"ResultCustomTableViewCell" bundle:nil] forCellReuseIdentifier:[ResultCustomTableViewCell reuseIdentifier]];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat height = 0.0;
if (tableView == resultTableView){
height = 44.0f;
}
return height;
}
i hope, it'll fix your problem
CellIdentifier I bet your cellForRowAtIndexPath is returning nil.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"LazyTableCell";
static NSString *PlaceholderCellIdentifier = #"PlaceholderCell";
NSUInteger nodeCount = [self.entries count];
if (nodeCount == 0 && indexPath.row == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PlaceholderCellIdentifier] autorelease];
}
cell.detailTextLabel.text = #"Loading…";
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (nodeCount > 0) {
AppRecord *appRecord = [self.entries objectAtIndex:indexPath.row];
cell.textLabel.text = appRecord.name;
if (!appRecord.appIcon)
{
if (self.mytable_view.dragging == NO && self.mytable_view.decelerating == NO)
{
[self startIconDownload:appRecord forIndexPath:indexPath];
}
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
else
{
cell.imageView.image = appRecord.appIcon;
}
}
return cell;
}
That's probably why [UITableView _configureCellForDisplay:forIndexPath:] is failing... because cellForRowAtIndexPath is returning a null value and then configureCellForDisplay is expecting a UITableViewCell.
Register your cell in the - (void)viewDidLoad method using
[self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:#"Your Reuse Identifier"];
if your are using storyboards and use this if you are using a custom cell.
[self.tableView registerNib:UINib nibWithNibName:#"Your File Name.xib" bundle:nil forCellReuseIdentifier:#"Your Reuse Identifier"]