Till today I thought I understood UITableView properly but that perception has changed as I have been fighting scrolling and content mismatch while scrolling issues.
I have a small table view with potentially 20-30 rows depending on user content. When I scroll (a bit faster than usual), the content gets mixed up. Some accessory views get interchanged, background colors get swapped or overwritten; sometimes even the text changes.
I use reuse identifiers for some of cells but I am not sure its even working out properly.
Issues:
Clearly a single reuse identifier is not cutting it in case — as the first and the last cell swap values.
With 3 reuse identifiers for first, last and remaining cells (contain settings), the accessory views get interchanged between some cells that contain settings, i.e. in some cases I use switch controls, in others I use an accessory detail button and there is blasphemy.
Even with 5 reuse identifiers for different types of content, the accessory views get mismatched with background colors of other cells.
I have been writing table views for a while and I have never encountered these issues before. So I have one simple question — When do you create reuse identifiers?
only when the text/image content is different?
when accessory views are same? i.e. for different accessory views create different reuse identifiers
I am completely lost on this so if you can really churn out an explanation, I would be really grateful.
EDIT: I have been working on this for the last 5 hours and have gone through a lot of literature and open/closed issues on StackOverflow. I understand what reusable cells are. The provided thread doesn't answer the very specific questions.
Here is some code:
// previously had 3 different types of cells; currently doing with one only
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
{
cell = [[ESBasicTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
static NSString *FirstCellId = #"First";
static NSString *SecondCellId = #"Second";
static NSString *ThirdCellId = #"Third";
static NSString *ForthCellId = #"Forth";
static NSString *FifthCellId = #"Fifth";
static NSString *SixthCellId = #"Sixth";
NSString *cellIdentifier = nil;
if (indexPath.section == kSectionFirst && indexPath.row == kRowFirst)
{
cellIdentifier = FirstCellId;
}
else if (indexPath.section == kSectionFirst && indexPath.row == kRowSecond)
{
cellIdentifier = SecondCellId;
}
else if (indexPath.section == kSectionSecond)
{
cellIdentifier = ThirdCellId;
}
else if (indexPath.section == kSectionThird)
{
cellIdentifier = ForthCellId;
}
else if (indexPath.section == kSectionSettings)
{
cellIdentifier = FifthCellId;
}
else if (indexPath.section == kSEctionFifth)
{
cellIdentifier = SixthCellId;
}
return cellIdentifier;
}
The configureCell:atIndexPath method results in other configuration calls; one of them being configuration for settings:
- (void)configureCellForSettings:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.selectionStyle = UITableViewCellSelectionStyleNone;
switch (indexPath.row)
{
case kRowNotificationSetting:
{
cell.textLabel.text = #"Notifications";
cell.accessoryType = UITableViewCellAccessoryDetailButton;
cell.imageView.image = [[UIImage imageNamed:#"cell_notification_icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
break;
}
case kRowSomeOtherSetting:
{
cell.textLabel.text = #"Auto";
cell.imageView.image = [[UIImage imageNamed:#"cell_auto_icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
[switchView addTarget:self action:#selector(changed:) forControlEvents:UIControlEventValueChanged];
[switchView setOn:...];
cell.accessoryView = switchView;
break;
}
default:
break;
}
}
Some meaningful text has been stripped out (unfortunately). The forth section is for the settings but this is just an example.
Edit: Here is configureCell:atIndexPath:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == kSectionFirst)
{
// ...
[self configureFirstCell:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionSecond)
{
// ...
[self configureSecondCell:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionThird)
{
// add ...
[self configureThirdCell:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionSettings)
{
// settings
[self configureCellForSettings:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionFifth)
{
// delete button
[self configureFifthCell:cell atIndexPath:indexPath];
}
}
Please note — I had to rename a lot of the code to have it on StackOverflow.
I only marked this as a duplicate because it sounds like you are struggling with the concept of what is actually happening when you call dequeueReusableCellWithIdentifier:
Whenever you call dequeueReusableCellWithIdentifier: to get a cell, try to conceptualize that you are being returned one of the cells that you have previously generated and added content to that has the same identifier (which is, in fact, exactly what you are doing). The cell that is being returned thusly, may already have accessory views/images set, etc, and you may need to unset/remove these depending on your use case.
If you have several types of cells (where the layout/content differs dramatically) then you may need to consider using multiple reuse identifiers - a reuse identifier for each type of cell, so you can more easily reuse cells, rather than resetting all accessory views/images/etc every time you reuse a cell.
Related
I have implemented the SWRevealController (a slide out menu), I referecned AppCoda.com for som help, here's the link (http://www.appcoda.com/ios-programming-sidebar-navigation-menu/).
I have succesfully implemented it, using the same way as AppCoda explains, setting cellIdentifiers for each cell in the sidebar and then styling them in the storyBoard. It all works great! However...
THE PROBLEM
So the problem is that I want sections in this table view, so that I can have different cells in different sections, but using the code I have now (which is below), I just get a repeated cell (the same cells as in my first section). I am having trouble with the sections because styling each cell based on their cell identifier.
This is what I get...
SO MY RESOLUTION (THAT DIDN'T WORK)
So what I tried to do was create multiple arrays, one for each section, and styled them like this,
if (indexPath.section == 1) {
cell.textLabel.text = [_fitnessItems objectAtIndex:indexPath.row];
if (indexPath.row == 0) {
cell.imageView.image = [UIImage imageNamed:#"torso-25.png"];
}
if (indexPath.row == 1) {
cell.imageView.image = [UIImage imageNamed:#"weightlift-25.png"];
}
if (indexPath.row == 2) {
cell.imageView.image = [UIImage imageNamed:#"barbell-25.png"];
}
}
But it worked, and I got what I wanted, however, it was very gilitchy when I tried to do an action when a cell was pressed, I was doing that like this...
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"test" sender:nil];
}
Now there might do be a way to fix this issue or fix the cell identifiers. Anyways that's what I tried doing.
WHAT I AM DOING NOW
So if you don't quite understand what I am doing, check out that AppCoda tutorial cause thats what I did. But I want sections between some cells. What I tried doing is this and it dosen;t work...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
NSString *CellIdentifier = [self.fitnessItems objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
else {
NSString *CellIdentifier = [self.menuItems objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
So I have two arrays of cell Identifiers and I try to allocate them to each section, but it dosen't work?
Any help would be greatly appreciated, and thanks in advance.
I have one UIViewController with UITableView inside,above table I have UISegmentControl, when I press on segment control I want to load a UItableCustomeCell, would you please help me in this implementation, I don't know how should I add them in cellForRowAtIndexPath, Since I have 3 different Custom cell
Here is the code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
if (indexPath.row == self.segmentedControl.selectedSegmentIndex == Test1) {
MytestsCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MytestsCell"];
if (!cell) {
cell = [[MyBooksCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"MytestsCell"];
}
return cell;
}
else if (indexPath.row == self.segmentedControl.selectedSegmentIndex == tests) {
testCell *cell = [tableView dequeueReusableCellWithIdentifier:#"testCell"];
if (!cell) {
cell = [[TestsCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"testsCell"];
}
return cell;
}
break;
case 1:
if (indexPath.row == self.segmentedControl.selectedSegmentIndex == PTest) {
PTestsCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PTestsCell"];
if (!cell) {
cell = [[PTestsCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"PTestsCell"];
}
return cell;
}
break;
}
I don't want to have 3 of them in one table, each custom cell is for one segment control
Thanks in advance!
One alternative I can think of is to switch the table views data source. But I would not recommend that. You could define a delegate of your data source and ask it for the table view cell for a selected segmented control. But this just moves the problem. I would stick to your approach.
So...here is what I would do. Starting with iOS6, you no longer need to check if your cell is nil after dequeuing from the tableview if you use
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath
You are guaranteed to get a cell back as long as the identifier exists. Also, it doesn't look like you need to do any additional configuration so something like this should work:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [NSString stringWithFormat:#"%d", self.segmentedControl.selectedSegmentIndex];
return [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
}
Edit: I forgot to add, that in order to use this, use numbers that correspond to the segments as the identifier for each cell.
I'm currently working on my second project which is focusing on CoreData and Custom Cells.
I have a custom cell with an image & label & switch, i'm trying to save the value of the switch to userdefaults when the value of the switch has changed. But i'm stuck with how to access each switch individually (there are 2 in the same section of my table view), so that when the switch is pressed the integer stored in userdefaults is instantly updated.
This is the code in the .m file concerning the custom cell (switchCell) apologises for any messy code etc, i'm pretty much 100% self taught without any advice/feedback on any mistakes i'm making.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
// Code for the first section, controlling which cells use the custom cell SwitchCell
if (indexPath.section == 0)
{
if(indexPath.row == 1 || indexPath.row == 2)
{
SwitchCell *switchCell = [tableView dequeueReusableCellWithIdentifier:#"SwitchCellIdentifier"];
cell = switchCell;
}
else
{
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"CellIdentifier"];
UISwitch *testSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = testSwitch;
}
}
}
// Each other section currently uses the standard cell type
else
{
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"CellIdentifier"];
}
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dictionary = [settingsTableData objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Settings"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
SwitchCell *switchCell = (SwitchCell *)cell;
[[NSUserDefaults standardUserDefaults] synchronize];
// Integers to store the on/off state of each switch (2)
NSInteger capsValue = [[NSUserDefaults standardUserDefaults] integerForKey:#"capitalsSwitchOn"];
NSInteger numbersValue = [[NSUserDefaults standardUserDefaults] integerForKey:#"numbersSwitchOn"];
NSLog(#"Upon load capsValue equals : %d", capsValue);
NSLog(#"upon load numbersValue equals : %d", numbersValue);
// Setting individual cell values for attributes such as image and text
if (indexPath.section == 0)
{
if(indexPath.row == 1)
{
switchCell.switchCellLabel.text = cellValue;
switchCell.switchCellImage.image = [UIImage imageNamed:#"capitalsImage.jpg"];
// Set to true or false depending on what you want the default value to be.
//switchCell.switchCellSwitch.on = FALSE;
if (capsValue == 1) {
[switchCell.switchCellSwitch setOn:NO animated:YES];
} else
[switchCell.switchCellSwitch setOn:YES animated:YES];
}
else if (indexPath.row == 2)
{
switchCell.switchCellLabel.text = cellValue;
switchCell.switchCellImage.image = [UIImage imageNamed:#"capitalsImage.jpg"];
if (numbersValue == 1) {
[switchCell.switchCellSwitch setOn:NO animated:YES];
} else
[switchCell.switchCellSwitch setOn:YES animated:YES];
}
else
{
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
else if (indexPath.section == 1)
{
if (indexPath.row == 0)
{
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else if (indexPath.row == 1)
{
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
else if (indexPath.section == 2)
{
if (indexPath.row == 0)
{
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else if (indexPath.row == 1 || indexPath.row == 2)
{
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
}
Thanks in advance to any help!
I would add that switch in your subclassed cell and not in the viewController. Then in the cell subclass create a delegate, which would call a method like switchDidChangeValue in the viewController. There set your defaults.
Add an IBAction to your SwitchCell.
In the header file add:
- (IBAction)switchChanged: (UISwitch*)sender;
And in the .m file apply:
- (IBAction)switchChanged: (UISwitch*)sender {
BOOL value = sender.isOn;
// Do your Core Data work here
}
You might have to add a property to SwitchCell, so that it knows what database entry to create/change.
Then go into your Storyboard or .nib file, click on the UISwitch, open the last Tab in the object inspector. There you should be able to see Send Events -> Value Changed. Drag a connection from that to your SwitchCell, select your IBAction and you should be good to go.
So many codes :-) and I'm not suer if I understand your mind or not. But I think maybe you can define two properties in your viewController for two switches, switchOne and switchTwo , and you assign them in function
tableView:cellForRowAtIndexPath:
I always do this when I have independent controls in grouped tableView.
Still I have some question about your code:
Do you mean the second and third cell in your first section are cells with switches?
I think in your code
if(indexPath.row == 1 || indexPath.row == 2){
SwitchCell *switchCell = [tableView dequeueReusableCellWithIdentifier:#"SwitchCellIdentifier"];
cell = switchCell;
}
the cell will always be nil, because you never build a cell with identifier "SwitchCellIdentifier"
I think you build switch controls for other cells of your first section, so I totally have no idea what you want
It's 2:00 in the morning here in China, I worked all night long and I'm very tried, so maybe your code is right and I misunderstood, if so, please let me know.
I've been going at this for about 3 hours now, and I'm finally throwing in the towel to y'all. I have 2 UITableViewin my view, one of which is a forum board to leave comments and what not, and the second UITableView is used to mention people. the issue I am having is that both tableview counts are being affected even if i only want to update just 1 of the tableviews.
I set the delegate/datasource in the viewdidload
self.mentionTableView.delegate = self;
self.mentionTableView.dataSource = self;
self.mentionTableView.tag = 1;
self.forumTable.delegate = self;
self.forumTable.dataSource = self;
self.forumTable.tag = 2;
and if i actually do not load feedArray which is where forumTable gets its data from, the mention portion works perfectly. I've figured out that if matchedNames.count<feedArray.count everything works fine, but if matchedNames.count>feedArray.count it crashes and this is the error i get
-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)
which means that i only have 1 item in feedArray and matchedNames has more than one.
inside of
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
i have used these codes to try to make it work and still nothing, ive even done combinations of them.
1)
if ([tableView isEqual: mentionTableView]){
NSLog(#"%#",matchedNames);
NSLog(#"%i",matchedNames.count);
return [matchedNames count];
} else if([tableView isEqual:forumTable]){
return [feedArray count];
}
2)
if (tableView == mentionTableView){
NSLog(#"%#",matchedNames);
NSLog(#"%i",matchedNames.count);
return [matchedNames count];
} else if(tableView == commentTable){
return [feedArray count];
}
3)
if (tableView.tag == 1){
NSLog(#"%#",matchedNames);
NSLog(#"%i",matchedNames.count);
return [matchedNames count];
} else if(tableView.tag == 2){
return [feedArray count];
}
and I know I didnt have to do the else if but I was just trying to be specific to maybe avoid this issue.
this is my cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.tag == 1){
CGAffineTransform transform = CGAffineTransformMakeRotation(3.14);
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.transform = transform;
cell.textLabel.text = [self.matchedNames objectAtIndex:indexPath.row];
return cell;
} else {
static NSString *CellIdentifier = #"commentCell";
commentsCustomCell *cell =(commentsCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[commentsCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSDictionary *feedPost = [feedArray objectAtIndex:indexPath.row];
NSString *checkIFempty = [feedPost objectForKey:#"isForum_empty"];
if (![checkIFempty isEqualToString:#"1"]) {
cell.noCommentsLabel.text = nil;
} else {
cell.noCommentsLabel.text = #"No Comments";
cell.forumComment = nil;
}
NSString *username =[feedPost objectForKey:#"Username"];
NSString *final_time =[feedPost objectForKey:#"final_time"];
NSString *userIDforPic =[feedPost objectForKey:#"UserID"];
finalComment = [feedPost objectForKey:#"comment"];
cell.forumComment.text = finalComment;
return cell;
}
}
if my question is confusing i do apologize, I haven't slept 36 hours. thanks for looking at my question!
You really really really should consider to refactor your code and separate this two tableViews in different viewControllers.
You can, for example, use containerViews inside your main viewController and put the tableview in the container view controllers.
TableView delegates use a lot of code, and set different tableViews to the same controller will always end up like this, messing the code and giving more trouble than it should be.
There are a few techniques you can use that will help clean up your code and allow for a less messy solution. I will take a wack at explaining this.
One first easy step is to create a property or method that gives you the array of data based on the tableView or tag:
- (NSArray *)dataForInteger:(NSUInteger)value {
return #[self.matchedNames, self.feedArray][value];
}
// you can also make this a readonly property for easier access
In order to use the above method you need to make sure the tag for the table that needs matchedNames is 0 and feedArray is 1 (or you could use a simple if/else statement and make the tags whatever you want.
Now look how easy this makes your future logic!
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
[[self dataForInteger:tableView.tag] count];
}
That's it!
Next, you could potentially create a method like:
- (UITableViewCell *)emptyCellForTableView:(UITableView *)tableView {
NSString *cellIdentifier = #[#"CellIdentifierONe", #"CellIdentifierTWO"][tableView.tag];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
// the only messy looking logic
if (!tableView.tag) { // tableView.tag == 0
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
CGAffineTransform transform = CGAffineTransformMakeRotation(3.14);
cell.transform = transform;
} else {
// make sure "CommentsCustomCell" is a class and not an instance (like your example)
cell = [[CommentsCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
}
return cell;
}
Then in your tableView:cellForRowAtIndexPath::
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self emptyCellForTableView:tableView];
NSArray *dataArray = [self dataForInteger:tableView.tag];
// setup all custom UITableViewCell's to have a property or setter "data"
if ([cell respondsToSelector:#selector(setData:)]) {
// I will explain this a bit later
cell.data = dataArray[indexPath.row];
} else {
// based on your example this was an NSString array
self.textLabel.text = dataArray[indexPath.row];
}
}
Now the cell.data = dataArray[indexPath.row]; is per Apple's example how setup data for custom UITableViewCells. Just create a property called data, that takes in it's setter looks something like this (for your example):
// CommentsCustomCell.m
- (void)setData:(id /*or custom class, in this case you use NSDictionary*/)data {
_data = data;
// NTOE: I just copied your example above, I am sure there is a nicer way to do this but you get the idea.
NSDictionary *feedPost = (NSDictionary *)data;
NSString *checkIFempty = [feedPost objectForKey:#"isForum_empty"];
if (![checkIFempty isEqualToString:#"1"]) {
cell.noCommentsLabel.text = nil;
} else {
cell.noCommentsLabel.text = #"No Comments";
cell.forumComment = nil;
}
NSString *username =[feedPost objectForKey:#"Username"];
NSString *final_time =[feedPost objectForKey:#"final_time"];
NSString *userIDforPic =[feedPost objectForKey:#"UserID"];
finalComment = [feedPost objectForKey:#"comment"];
cell.forumComment.text = finalComment;
}
The reason why a solution like this is so beautiful is if you ever wanted to use a different custom UITableViewCell all you would need to do is change the Empty Cell Creation method to create that class, and that is basically it (This also allows you to make all of your cell's IBOutlets private!). As long as the new class has a data property your main controller does not care! It just sends the data through. This also allows you to scale it appropriately. If all the tableView's used custom cells you could easily have a dozen tableviews in the same viewController without needing much extra logic (just add it the array, set the tag, and make sure the cell creation method creates the appropriate cell!).
I typed this up pretty quickly so there is probably some missing logic or typos. I will fix any if they are pointed out. Good luck.
I am an iOS newbie. I am using a checkmark to in a UITableView, and storing the checked value in a local database. When I load the app for the first time, I want to set the value of the checkmark depending on which value exists in the db. How would I do that? Presently this is what I do -
- (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];
}
if ([indexPath compare:self.lastIndexPath] == NSOrderedSame)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Set up the cell...
NSString *cellValue = [[self countryNames] objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
and then in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// some stuff
self.lastIndexPath = indexPath;
[tableView reloadData];
}
Are you asking simply how and when to set the checkmark or are you asking how to populate a table from a database (eg Core Data)?
From your code, the only data you represent is in [self countryNames] and it's not clear under what circumstances you'd want the cell to display a checkmark. Whatever that is, just check the condition and set the checkmark when you are configuring your cell for data (after your "Set up the cell..." comment).
Example if you stored the users country and checked that cell:
// get the current country name
NSString *cellValue = [[self countryNames] objectAtIndex:indexPath.row];
// configure the cell
cell.textLLabel.text = cellValue;
UITableViewCellAccessoryType accessory = UITableViewCellAccessoryNone;
if ([cellValue isEqualToString:self.usersCountry]) {
accessory = UITableViewCellAccessoryCheckmark;
}
cell.accessoryType = accessory;
If you have static table data, then you simply need to store the section and row of the selected table view cell. If you have dynamic data, then you will need to store the unique data for that selected cell in the database and compare that with the cell's content on load. When you are loading your cells in cellForRowAtIndexPath:, simply set that cell's accessory to UITableViewCellAccessoryCheckmark as well as set self.lastIndexPath = indexPath for comparison later.
Also, I typically use [indexPath isEqual:self.lastIndexPath] instead of compare:. Doesn't really make a difference either way, just for readability.