UITableView isn't refreshing properly after changing dataSource - iphone

I have a UITableView with several datasources. This is because, I need to switch the data with a UISegmentedControl, and if I add them as subviews, I cannot use the statusBar to scroll up, etc.
At first, I show a login screen:
self.tableView.dataSource = loginTableView;
self.tableView.delegate = loginTableView;
[self.tableView reloadData];
Then, once the user has logged in, I do the following to change to index:1 of the segmentedControler, which is their profile:
self.tableView.dataSource = profileTableView;
self.tableView.delegate = profileTableView;
[self.tableView reloadData];
However, the table view updates, but is a bit of a mix between the two dataSources. Some of the text has changed, some is overlapping, while some of it is completely missing.
Is there another way I should be changing the dataSource for a UITableView?
Thx

I had the exact same problem. My solution was to make the tableView hidden, change it's source, reload the data and make the tableView visible again.
Example in C# (MonoTouch):
tableView.Hidden = true;
tableView.Source = newTableViewSource;
tableView.ReloadData();
tableView.Hidden = false;

Not sure why this is happening from the code you have posted.
Instead of changing the delegate and datasource, swap out whatever ivar represents the data being displayed:
- (NSArray*)tableData{
if(showingLogin)
return self.loginData;
return self.profileData;
}
Now you only have 1 UITableViewController instance, but a BOOL to tell you which datasource to use.

The table view is caching the cells internally it uses for displaying your data. So if you change the data source you should also check that your is - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method is updating all the cells to the correct new values.
From your description it sounds like it is using the cached UITableViewCell instances and is not updating it to the correct new data in all cases. Perhaps code like this:
- (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];
cell.frame = CGRectZero;
cell.textLabel.font = //Set font;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = #"My Text for this cell"; // <==== Not good! Move it out of this if block
}
// Set cell text here
}
The simplest solution I found for this sort of problem is to just make the String you use for the cell creation (CellIdentifier) depending of the data Source. In this case you don't mix the cell of the different content types (and this helps you also if the cells need to have a different look depending on the mode).

I had this problem, turned out it was because my CellIdentifiers were the same...
static NSString *CellIdentifier = #"Cell";
Change one of them and the cells layout properly
static NSString *CellIdentifier2 = #"Cell2";

Wow, that's freaky.
The last time I did something like this, I simply used multiple views, hiding one and showing another when the segmented control was tapped. There are other possible solutions, but this is probably easiest and perhaps most efficient.

I have the same issue and what you have to do is use a different cell identifier within - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.
if (self.segmentedControl.selectedSegmentIndex == 0) {
self.cellIdentifier = #"segmentOne";
} else {
caseAtIndexPath = [self.awaitingReviewCaseList caseAtIndex:indexPath.row];
self.cellIdentifier = #"segmentTwo";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath];

Related

Custom CellIdentifier is Null When Using Search Display Controller

In my tableview have custom cells that I initialize from a UITableViewCell class. I have sections for first letters of records and have an indexPath that is being created dynamically.
I wanted to add a search display controller to my tableview. So I did, created all methods to filter data. I am sure that my functions are working well because I am printing array count to screen for search results.
My problem is that the first time view loads, the data is on the screen. But when I hit the search input and type a letter, than I get 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:' error. After I used a breakpoint I saw that my custom cell is nil after searching. Data is exist, but cell is not being initialized.
Here is the code I use for custom cell initializing:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ObjectCell";
SpeakerCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *myObject = [[sections valueForKey:[[[sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.label1.text = [myObject objectForKey:#"myValue"];
return cell;
}
I believe I made a mistake when putting controls in IB. So I added screenshots of objects:
Connections inspector for my table view
Connections inspector for my search display controller
EDIT: Problem is actually solved, I have used a UISearchBar instead of Search Display Controller but I guess this issue remains unsolved. So I'm willing to try any ways to make it work.
As of here search display controller question,
you need to access the self.tableView instead of tableView:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"CellId"];
// do your thing
return cell;
}
For those using iOS 5 and StoryBoards, you would want to use the following method instead of initWithIdentifier:
initWithStyle:(UITableViewCellStyle)stylereuseIdentifier:(NSString *)reuseIdentifier
Example:
NSString *cellIdentifier = #"ListItemCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
I'm not sure about how this should work in storeboarding.
But normally you would check if the [tableView dequeueReusableCellWithIdentifier:CellIdentifier] returns a cell.
Because if the cell in not loaded before or there aren't any cells to reuse you will have to create a new cell:
SpeakerCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[SpeakerCell alloc] initWithIdentifier: CellIdentifier];
}
Also when in declaring local variables in Objective-C we tent not to capitalize the first letter.
I had the same issue, with custom cells (built in Storyboard) not being drawn as soon as the first letter was put in the search field. The search was successful however.
Finally I found a good tutorial from Brenna Blackwell suggesting to configure manually the cell drawing in the corresponding subclass of UITableViewCell, adding UILabels and other items.

UITableViewCell ShouldIndentWhenEditing Issues

Im having issues the editing mode of the tableview. When we set the table to edit mode it indents the row cells to the right for edit field on the right. I want to stop this from happening. I have set the cell.shouldIndentWhileEditing = NO; but this doesn't change anything.
Another thing to note is this cell is programmatically built on the fly e.g.
static NSString *CellIdentifier = #"ListingCustomCell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 34) reuseIdentifier:CellIdentifier];
}
cell.shouldIndentWhileEditing = NO;
//SETUP CELL FIELDS
//return cell;
Any ideas on what im doing wrong?
Thanks
Perhaps your UITableViewDelegate is returning YES in - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath. If the delegate method is implemented, it'll override the value on the cell.
Did you read this part of the documentation?
This property has an effect only on table views created in the grouped
style (UITableViewStyleGrouped); it has no effect on
UITableViewStylePlain table views.
Maybe that’s your case.

update uitableview cell object

i have a tableview that contains a uiwebview in its first row. i would like to change this tables' webview object with new one when user clicks a button. i am using the code given below but it does not work fine. older object is there and the newer one is over it although i recreate the webview. how can i remove the older one from cell?
thanks...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog(#"NİL.......");
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
} else {
NSLog(#"NOT NİL.......");
}
[cell addSubview:webView];
return cell;
}
Since you are using "dequeueReusableCellWithIdentifier", your should reconfigure the cell each time when the cell is displayed.
Please remember that the cells with same identity will be reused. It's better to set the same identity to one particular type of cells, typically cells with same subviews and layout.
This is sample for how to load data and reconfigure a cell: http://code.google.com/p/tweetero/source/browse/trunk/Classes/MessageListController.m
Here is a tutorial to get familiar with UITableView:
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/TableView_iPhone/CreateConfigureTableView/CreateConfigureTableView.html

UITableViewDelegate methods

Here is an xcode project that I just did to ask this question:
http://www.mediafire.com/?z26ufsfhby62br9
Open the log and run it. You will find that it outputs display: x and create: x where x is a number 0 to 49 and corresponds to the cell of the same number. It should only output to 22 before any scrolling is performed as Apple are always boasting that their tableviews are loaded as needed.
It basically shows that tableView:willDisplayCell:forRowAtIndexPath: and tableView:cellForRowAtIndexPath: are fired for each cell pretty much as soon as the tableview appears, why is this?
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"create: %i", indexPath.row);
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
cell.textLabel.text = [NSString stringWithFormat:#"%i", indexPath.row];
return cell;
}
- (void) tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"display: %i", indexPath.row);
}
Why are the above meothds called just after the tableView loads (and just before each cell appears)? Surely they should be called just before each cell appears only?
These are the default delegate methods.. This will be be called for each cell everytime.
You use willDisplayCell:forRowAtIndexPath: to configure things like font and text color. In the newer version of the iPhone, with certain table configurations, if you configure things like the label text color in the tableView:cellForRowAtIndexPath: method, your changes will be lost at some point before the cell is actually displayed. Here you can do things like change the label's color, adjust background highlighting, such things as these.
If your table view is reloading before it actually fully displays, that could cause the behavior you're seeing. Then the cells would get initialized, prepared for display, but then all of that would be lost (before even shown on screen) as the table is reloaded.

UITableView not scrolling smoothly...(iPhone SDK) ..!

UITableView not scrolling smoothly...(iPhone SDK) ..!!
I have implemented UITableView DataSource and Delegate methods in an individual separate classes.(one for delegate and one for datasource) in main program i write only:
//assume that all objects are allocated
ObjTableView.dataSource=ObjDataSource;
ObjTableView.delegate = ObjDelegate;
[self.view addSubView: ObjTableView];
when i run this code , UITable view appears but when i try to scroll it, it doesn't scroll smoothly.
I have also checked that UITableViewCell doesn't redraw once the cell is initialized.
can any one tell me why this happens ? How can i solve this problem ??
From comments:
ListDataSource *ObjListDataSource = [[ListDataSource alloc]initWithArray:[[sender object] valueForKey:#"List"]];
ListDelegate *ObjListDelegate = [[ListDelegate alloc]initWithArray:[[sender object] valueForKey:#"List"]];
tblList = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320, 460)];
tblList.dataSource = ObjListDataSource; tblList.delegate = ObjListDelegate;
[self.view addSubview:tblList]; [tblShopList release];
More from comments:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:#"%i",indexPath.row];
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,320,100) reuseIdentifier:CellIdentifier] autorelease];
//custom cell code
}
return cell;
}
More Information:
I have used NSNotification which notifies to current class when parsing is complete, after receiving notification , current class method calls DataSource, Delegate methods (which is defined in a separate class file).
So UItableViewCell customization (which is in ListDataSource) and table view(in current class) both are in different classes.
A problem is
NSString *CellIdentifier = [NSString stringWithFormat:#"%i",indexPath.row];
The id needs to be the same for all cells of the same class, otherwise you never reuse them. As you can see in most examples, it is indeed a constant in most (all?) cases.
Little explaination on the reuseIdentifier: every time a cell gets out of screen, you can reuse it instead of creating a new one. To reuse it, you need a cell in queue with the same identifier as the one you pass to dequeueReusableCellWithIdentifier. The way you did, the cells are never reused, because each id is unique (they may or may not be reused in case a row reappears on screen, depending on queue size, which is not configurable AFAIK). This is why personalization of the cell should happen OUTSIDE the "cell == nil" block. Long story short, you are using the reuseIdentifier not as intendend.
I think Michele is correct, but I would also add that it looks like you are doing your cell customization where the cell gets created. What you should be doing is something more like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = (UITableViewCell)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,320,100) reuseIdentifier:CellIdentifier] autorelease];
//custom REUSABLE cell code here, e.g. text color, etc.
}
NSString *cellText = [dataArray objectAtIndex:indexPath.row]; //assuming you have a simple array for your data
cell.textLabel.text = cellText;
return cell;
}
I would also add that I'm not sure why you are able to run the app with the code you have here, since UITableViewCell cell = ... is an invalid initializer. It should be UITableViewCell *cell = ....
It would be helpful to see how you are customizing your cell, since without that it's hard to see what's happening.