iPhone Sdk: UITableViewCells copy themselves randomly - iphone

i have been trying to figure this out but i just can't....
for some reason, everytime my UITableView reaches a certain length due to the number of rows and sections, cells seem to randomly copy themselves into different cells at the end of the table without me wanting or programming it... Anyone else have this issue or knows how it's resolved? Any help is appreciated! Tanks.
Edit:
The "row" property is a counter which gets counted up to 13 and is then reset to 0 and counted up again and i always want the string "newUpdate" to be displayed in the corresponding row but at the same time i don't want the rest of the cells to be blank i want them to keep their old content until they're overwritten because the counter is starting at 0 again.
#import "ServerUpdateViewController.h"
#implementation ServerUpdateViewController
#synthesize newUpdate;
#synthesize row;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 15;
}
- (NSString *)tableView: (UITableView *)table titleForHeaderInSection:(NSInteger) section {
return #"All Updates to Server";
}
// 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] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath.row == self.row) {
cell.textLabel.text = self.newUpdate;
}
// Set up the cell...
return cell;
}
- (void)dealloc {
[super dealloc];
}
#end

You're re-using cells. In your cellForRowAtIndexPath: method, you need to fully configure the cell every time it's called.

There are a few things that can cause this and I can't be specific without seeing code, but it comes down to the fact that cells are reused. The entire content of the cell will have to be re-set/redrawn every time cellForRowAtIndexPath is called.

Related

UITableView tableView:cellForRowAtIndexPath: not getting called

I have 3 table views in one view and I was wondering why the tableView:cellForRowAtIndexPath: was not getting called.
#pragma mark -
#pragma mark <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.mainVoucherTableViewController)
[self setSelectedIndex:indexPath.row];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.mainVoucherTableViewController){
return 10;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.mainVoucherTableViewController){
static NSString *MyIdentifier = #"MyReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
cell.textLabel.text = #"THISTEXT";
return cell;
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (tableView == self.mainVoucherTableViewController)
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// The header for the section is the region name -- get this from the region at the section index.
if (tableView == self.mainVoucherTableViewController){
NSString * myString = [NSString stringWithFormat:#"HELLLO WORLD"];
return myString;
}
}
WOULD anyone know why this is? Basically this doesn't create any cell or display cells. It just displays the table views. :(
Just to consolidate a few things from above:
From your naming, your tableView is called mainVoucherTableViewController - just want to confirm that this is indeed a UITableView and not a UITableViewController? If it's a UITableViewController then the rest of this won't work for obvious reasons (or not so obvious - let me know and can explain further)
Make sure you have set the current viewController as the tableView's delegate and dataSource, either with the code below or in Interface Builder if you're using a XIB
self.mainVoucherTableViewController.delegate = self;
self.mainVoucherTableViewController.dataSource = self;
Make sure your numberOfRowsInSection function is being called and that you're returning non-zero (put in NSLogs, etc) and do the same for numberOfSections as well (actually numberOfSections isn't required if you're only using 1 section) - see UITableViewDataSource Protocol Reference: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html
As per previous post, log your cellForRow (if points #1-3 are checked and working) at the beginning to make sure it's triggered, and just before the return. Also do an NSLog of the cell you're returning just to make sure it isn't nil.
Start off by logging inside your tableView:cellForRowAtIndexPath: method to see if it gets called at all outside your if statement as well as inside to help narrow down the issue.
Also try instead of comparing your:
tableView == self.mainVoucherTableViewController
Set the tableViews to have tag values instead. Then you can do:
if(tableView.tag == 100){ // tag number we assigned self.mainVoucherTableViewController via IB
//do your stuff here
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.mainVoucherTableViewController)
{
return 10;
}
else
{retun 5;
}
}
It display row in first table 10, second table show 5 rows.
The order of instance declaration does matter. For example, if you have a ivar called tableView:
WRONG
self.tableView.delegate = self;
self.tableView = [UITableView alloc] init];
CORRECT
self.tableView = [UITableView alloc] init];
self.tableView.delegate = self;
check UITableView Object Frame Size. maybe Frame size is not enough to draw Cell.

Adding dynamic sub-rows by selecting tableview row in tableview iPhone errors?

I want to add row dynamically. I have tableview list of building names. If some one choose building(didSelectRowAtIndexPath) then respective floors of building should get added dynamically as subrow. Its like maximizing and minimizing the subrow on respective building list selection. How do I do this. Thanks in advance...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// There is only one section.
if (tableView == indoortable || tableView == indoortable_iPad)
{
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of time zone names.
if (tableView == indoortable || tableView == indoortable_iPad)
{
return [indoorZones count];
}
}
cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == indoortable || tableView == indoortable_iPad)
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleGray; //cell bg
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Set up the cell.
//cell.textLabel.text = [copyListOfItems objectAtIndex:indexPath.row];
cell.textLabel.text =[indoorZones objectAtIndex: indexPath.row];
//[cell setIndentationLevel:[[self.indoorZones objectAtIndex:indexPath.row] intValue]];
return cell;
}
}
didSlectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
zonesFloor = [[NSMutableArray alloc]init];
zonesFloorA = [[NSArray alloc] initWithObjects:#"Gr fl",#"1st fl",#"2nd fl",nil];
[zonesFloor addObject:zonesFloorA];
if (tableView == indoortable )
{
NSUInteger i=indexPath.row+1;
for (NSArray *count in self.indoorZones) //app is crashing here giving error.......Collection <__NSArrayM: 0x4b1d550> was mutated while being enumerated.
{
[zonesFloor addObject:[NSIndexPath indexPathForRow:i inSection:0]];
[self.indoorZones insertObject:zonesFloor atIndex:i++];
}
[[self indoortable] beginUpdates];
[[self indoortable] insertRowsAtIndexPaths:(NSArray *)zonesFloor withRowAnimation:UITableViewRowAnimationNone];
[[self indoortable] endUpdates];
}
if (tableView == indoortable_iPad )
{
//some logic
}
[tableView deselectRowAtIndexPath:selectedIndexPath animated:NO];
}
It Gives following error [__NSArrayI compare:]: Or [NSIndexPath _fastCStringContents:]: unrecognized selector sent to instance. I tried many ways but may be I am lacking somewhere. Please suggest. thanks in advance.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSIndexPath *selectedIndexPath = [self.indoortable indexPathForSelectedRow];
zonesFloorA = [[NSArray alloc] initWithObjects:#"Gr fl",#"1st fl",#"2nd fl",nil];
if (tableView == indoortable )
{
for (NSString *str in zonesFloorA) {
[indoorZones addObject:str];
}
//[[self indoortable] beginUpdates];
//[[self indoortable] insertRowsAtIndexPaths:(NSArray *)zonesFloor withRowAnimation:UITableViewRowAnimationNone];
//[[self indoortable] endUpdates];
}
if (tableView == indoortable_iPad )
{
//some logic
}
[tableView reloadData];
}
may this meet your requirement
Okay, so not to sound mean, but there are almost too many issues here to count.
Let's start with a basic explanation of how tableView's work so that you can start to fix this:
First, the tableView asks how many sections are in the table by calling:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
}
In your code, you simply tell it that it has one section. However, in your later code, when you try to add rows to your table, you tell it that you want to add your rows to a second section (with an index of 1). Therefore, you either need to add these rows to section 0 instead, or update the above method to tell it that, sometimes, there are two sections.
Second, the tableView asks how many rows are in each section of the table by calling:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
}
In your code, you are simply returning the number of zones. However, like above, you need to include the rows that you have added to your table. If you are adding them to a different section, then you need to return different values, depending on how many rows are in the section with the index asked for in the section variable. If they are all in the same section, then you need to add them up and return the correct value.
Third, the tableView asks for an actual cell for the row by calling:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
}
In your code, you are only returning a cell which has data populated by the indoorZones array, but you also need to supply cells which are configured properly for the specific zone/floor. Again, you either need to determine this by section number or row number as appropriate.
Finally, when you click on a row, the tableview tells you by calling the following method:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
In this method, you need to update your data source that is used by the previous functions so that when they get called again, they will provide the correct data. Your data source must mirror the way that you want your table view to look. In your case, you have an array called indoorZones. This is good if you just want to display a list of zones, which is what you start off doing. However, when you want to add more rows, you need to add more rows to your data source first, so that when the tableView starts this process over, it is already there.
If you want everything to stay in one section, then I would come up with a data source that can include both types of rows, and be able to distinguish between them so that cellForRowAtIndexPath can create the proper type of cell and return it.
If you want two sections, then I would add a second array for the second section (since it is not the same type of data) and return the appropriate values in each of these methods, based on which array you need to use for that section.
I hope this helps!

Combine static and prototype content in a table view

Is there a way to combine static tableview cells (static content) with dynamic tableview cells (prototype content) using storyboard?
I suggest you treat your table as dynamic, but include the cells you always want at the top. In the Storyboard, place a UITableViewController and have it use a dynamic table. Add as many UITableViewCell prototypes to the table as you need. Say, one each for your static cells, and one to represent the variable cells.
In your UITableViewDataSource class:
#define NUMBER_OF_STATIC_CELLS 3
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dynamicModel count] + NUMBER_OF_STATIC_CELLS;
}
and, then
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row < NUMBER_OF_STATIC_CELLS) {
// dequeue and configure my static cell for indexPath.row
NSString *cellIdentifier = ... // id for one of my static cells
} else {
// normal dynamic logic here
NSString *cellIdentifier = #"DynamicCellID"
// dequeue and configure for [self.myDynamicModel objectAtIndex:indexPath.row]
}
}
I had a problem, although it was a slight variant of this. I actually wanted to mix dynamic and static cells but in different groups. Meaning group 1 would have static only cells and group 2 would have dynamic cells.
I accomplished this by actually hard coding static cell values (based on their prototype cell identifiers). The dynamic sections would have normal dynamically populated content. Here is some example code in case anyone else has the same issue:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == 1){
return #"Dynamic Cells";
}
if (section == 0){
return #"Static Cells";
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
return 1; //However many static cells you want
} else {
return [_yourArray count];
}
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
if (indexPath.section == 0) {
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;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
Since no one has actually provided a real answer to the problem (using both static and prototype cells in the same table view), I figured I'd chime in.
It can be done!
Create your static cells as you see fit.
For the sections that need a dynamic cell, if you are NOT using standard UITableViewCell type, you'll need to create your custom one in a separate Nib, otherwise you can use the standard ones.
Then implement the following delegates. Basically for each of these delegates, for the static stuff we want to call super, for the dynamic, we return our values.
First, IF you need to selectively show your dynamic section, you'll want to implement the numberOfSectionsInTableView (otherwise you can leave this delegate out):
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
int staticSections = 1;
int dynamicSections = 1;
if (SOME_BOOLEAN) {
return staticSections + dynamicSections;
} else {
return staticSections;
}
}
Then, you need to implement numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 1) {
return A_COUNT;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
Then, you need to implement heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return 44.0f;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
Then indentationLevelForRowAtIndexPath:
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return 1; // or manually set in IB (Storyboard)
} else {
return [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath]; // or 0
}
}
Finally, cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
SomeObject *obj = self.someArray[indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DynamicCell" forIndexPath:indexPath];
cell.textLabel.text = obj.textValue;
return cell;
} else {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
You can always make one you your tableviews appear similar to the static table but define it in code. Set the sections, amount or rows per section, headers etc. through the delegate methods.
Unfortunately, this is not possible since static table views must be in a UITableViewController and that only allows one tableview.
What you need to do is make three more dynamic UITableviewCell's and load them individually for the first three rows where you want the static content.
If you aren't sure how to do this, let me know and I can find some code.
You can't have one tableview be static and the other dynamic in the same view controller so you will need to make them both dynamic. In the first tableview you will configure the cells in code on initializing the view controller never update them.
Add a UIViewController to your storyboard.
Add two Table Views (Not
TableViewControllers) to the UIView Controller.
Select each tableView and configure both for dynamic cells.
Build and attach your view controller. 2 tableview on a single view explains that step.
As another option you can achieve a similar look by embedding your dynamic tableview in part of a view similar to the link in step 4 and then do whatever you wanted to in the rest of the view to setup what you were planning to do with static cells by using scrollviews, labels, and buttons.
You could also create buttons (one for each static cell you have) that are styled like your cells and place them in the tableHeaderView or tableFooterView of the UITableView; those buttons are just views after all.
You'll need to add some logic for making selections on the buttons vs. the cells so it maintains the usual look and feel.
Of course, this assumes that you want to insert static cells into your table view at the top or bottom of the table.
One way to have dynamic content in a static table view is to clone cells where additional rows are needed.
For the dynamic section of my table view, I lay out one or more cells in Interface Builder. At runtime, I can clone those by archiving using NSCoder and then unarchiving.
It works, but is not necessarily prettier than starting with a dynamic prototype table view and creating static rows from there.
It fails with standard table view cells. The lazily created text labels are not laid out correctly. Hence I used UITableViewCell subclasses where I take care of archiving and unarchiving subviews.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == kContactsSection) {
NSArray *contacts = self.contacts;
Contact *contact = [contacts objectAtIndex:indexPath.row];
NSString *name = contact.name;
NSString *role = contact.role;
if ([role length] == 0) {
NNContactDefaultTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier : #"contactDefault"];
if (cell == nil) {
NNContactDefaultTableViewCell *template = (id)[super tableView : tableView
cellForRowAtIndexPath :[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:template];
cell = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
cell.contactTextLabel.text = name;
return cell;
}
else {
NNContactDetailTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier : #"contactDetail"];
if (cell == nil) {
NNContactDetailTableViewCell *template = (id)[super tableView : tableView
cellForRowAtIndexPath :[NSIndexPath indexPathForRow:1 inSection:kContactsSection]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:template];
cell = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
cell.contactTextLabel.text = name;
cell.contactDetailTextLabel.text = role;
return cell;
}
}
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
In the above example I have two cell types. Both laid out in Interface Builder as part of a static table view.
To get dynamic content in one section, I also need to override the following methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == kContactsSection) {
NSArray *contacts = self.contacts;
NSUInteger contactCount = [contacts count];
return contactCount;
}
return [super tableView:tableView numberOfRowsInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger section = indexPath.section;
NSInteger row = indexPath.row;
if (section == kContactsSection) {
return [super tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
}
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger section = indexPath.section;
if (section == kContactsSection) {
CGFloat indentation = [super tableView:tableView indentationLevelForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
return indentation;
}
CGFloat indentation = [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
return indentation;
}

UITableview strange behaviour

I have a UITableView with a top navigation bar. The data for the UITableView comes from an array which contains more than 20 objects.
Everything is fine so far. However sometimes when i do repeated scrolling (fast), I find last row being repeated, sometimes gets cut into half, overwritten.
I am new to iPhone development and have no clue why this happens.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [appDelegate.preList count];
}
// 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] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
Item *i=[appDelegate.preList objectAtIndex:indexPath.row];
cell.textLabel.text=i.iName;
cell.accessoryType=UITableViewCellAccessoryNone;
return cell;
}
I have attached a screenshot of my problem as well. Notice how the navigation bar and the last cell are.
Help would be greatly appreciated
This looks like you have added two identical table views to your view. If you place a break point on numberOfSections… and then inspect the tableView object, I bet you will find two different table views. Start by looking for places in your code where you [self.view addSubview:tableView] or something similar. Remember, if you are using IB to setup your table, you do not need to programmatically add it.
I think you are seeing this when scrolling fast because only then the tableView bounces leaving some content offset. You have probably added 2 tableViews back to back.

UITableViewCell: how to verify the kind of accessoryType in all cells?

I have a UITableView in that some cells are marked with UITableViewCellAccessoryCheckmark at the initialization of the view.
When the user selects another row, I have to check if the maximum number of selected rows was achieved before. To do that, I used the code bellow:
- (NSInteger)tableView:(UITableView *)tableView numberOfSelectedRowsInSection:(NSInteger)section{
NSInteger numberOfRows = [self tableView:tableView numberOfRowsInSection:section];
NSInteger numberOfSelectedRows = 0;
for (int i = 0; i < numberOfRows; i++) {
UITableViewCell *otherCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:section]];
if (otherCell.accessoryType == UITableViewCellAccessoryCheckmark) {
numberOfSelectedRows++;
}
}
return numberOfSelectedRows;
}
If my number of rows is, as example, 20, the variable numberOfRows is setted correctly with 20. Lets say that 13 rows already are marked with UITableViewCellAccessoryCheckmark. So, numberOfSelectedRows should be 13 after the loop, but only the marked and VISIBLE cells are considered. So, if I have 9 cells showed and 7 are marked, the numberOfSelectedRows returns 7 instead of 13 (but the for iterate 20 times, as expected).
Is this a correct behavior of UITableView or it is a bug of iPhone simulator?
Thanks in advance.
Yes, it works as designed. You should never store model data in your views. UITableView knows nothing about the data, it only displays cells (and throws them aways as soon as they scroll off the screen). You need to store the checkmark state of each cell in a model object (e.g. an array) that you then access from your view controller.
This is correct behavior.
The UITableView is not a list. The system caches cell that are off screen to save memory and CPU and they can not be iterated over in a manner that makes sense.
Ok, you should keep track of the model/data and the tableView will keep track of displaying it. I have had some problems with this until I accepted that uitableView is not a list:)
So, have an array of objects that each corresponds to the data in the a cell. When building the individual cells like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"categoryCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
Item *item = [self.itemList objectAtIndex:indexPath.row];
[cell.textLabel setText:[item itemBrand]]; //notice that here we set the cell values
return cell;
}
The when a user clicks you change you model like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"IndexPat.row%i", indexPath.row);
Item item = (Item*) [self.itemList objectAtIndex:indexPath.row];
//change the state of item
}
This way the tableView will update to resemble the model/data, you just managed the model.