UITableView Scroll slowly - iphone

i got the problem in my apps, i have UITableView and it's scroll slowly, not as fast as the other application, even i didn't create any object or add subview in my table
this is my code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *searchingIdentifier = #"searchingIdentifierCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:searchingIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:searchingIdentifier]autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.detailTextLabel.text =[[self.dataStoreByCategory objectAtIndex:indexPath.row]objectForKey:#"storeLevel"];
cell.textLabel.text = [listStore objectAtIndex:indexPath.row];
cell.imageView.image = [[self.dataStoreByCategory objectAtIndex:indexPath.row] objectForKey:#"storeIcon"];
}
somebody can help me.??

This mainly happens when the contents you are using in the cell is of large size.
In your case, the images you are using in the cells might be of very large size. You can check it by commenting the code and testing it.
To sort out the problem, make an array of thumb nail images to be displayed on the cell instead of the original images. You could find some methods to make the thumb nail of an image by reducing the height and width of image.
If you use the thumb nail images inside the tableview, your table would scroll faster. When the user select any table row, you can display the full image in your next view as required in your application.

Is your image that you put into UITableViewCell is big?
I think you can try to comment the line loading the image to see if it is faster. I don't see any problems in your code

What is the size of your images ?
In the same idea, what is the length of the text used ?
If your images are too big, it may slow down the scroll. The same for the text (but it needs a lot of text ^^)

Just try restart your device. Sometimes device tend to go slow if it is "on" for many days! Believe me!

Related

UITableView renames every eighth cell

I have a UITableView in my MainViewController. When a user taps a cell,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedRow = indexPath;
....
[self performSegueWithIdentifier:#"OtherViewControllerSegue" sender:self];
}
and they are taken to another UIViewController (let's call it OtherViewController). In OtherViewController, the name for the selected cell is set. When OtherViewController is dismissed, it updates the cell in MainViewController with the new name:
[[[mainvc.myTableView cellForRowAtIndexPath:mainvc.selectedRow] textLabel] setText:namecell.textField.text];
[self.navigationController popViewControllerAnimated:YES];
This all works fine until I have more cells than will fit on the screen. If there are more cells than will fit on the screen (8 for iPhone or 16 for iPad), then this will also set the name for every eighth or sixteenth cell respectively. Any ideas on what I am doing wrong?
Update:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [pointsTableView dequeueReusableCellWithIdentifier:#"myTableCell"];
return cell;
}
This is due to cell-reuse and you are mixing up your model with your view (in the MVC context).
A table-cell is a transient thing, once it goes off the screen it is reused (instead of creating new cells) when another cell is needed. This is what the dequeueReusableCellWithIdentifier: method does.
This means you can't store data in there and expect it to still be valid later on. In this example you are trying to store the name in the table cell. The reason to set a property (like the label text) on any view object is purely for display, not for storage. So to solve this problem you should maintain a list of objects in your model (this could be in separate classes or in an array in your mainvc object for example). Then in cellForRowAtIndexPath: you should set the label text every time - even when there should be no label you need to set it to nil or an empty string because the cells are re-used it might contain something from the last time it was used.
Update:
Instead of calling cellForRowAtIndexPath: yourself and setting its text, you should set the text in your model using a method or property in your controller and then tell the table view to reload that cell. The code might look something like this:
// This code is in where you want to set the text from
[mainvc setText:someText forIndexPath:indexPath];
.. and in your main view controller:
- (void)setText(NSString*)newText forIndexPath:(NSIndexPath*)indexPath
{
// Store the text in your model here...
...
// If the view is loaded, the table view should reload the cell.
if(self.isViewLoaded)
{
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
The table view will then call cellForRowAtIndexPath: where the text will be set correctly. This may seem a little convoluted at first, but when you get used to using the Model-View-Controller design pattern you will find that keeping the jobs of each MVC component separate like this will mean your code is tidier, easier to understand, has less bugs, is easier to update/extend, etc.
You're trying to store data (the new name) in a view (the cell's label). What's probably happening is that when you re-use cells in the data source's cellForRowAtIndexPath method, some of them are ones that have had this text set for them and it's still there.
The better idea is to make your changes in whatever array you use as cell information and then reload the table view to make the changes visible.
As I suppose, you shouldn't call cellForRowAtIndexPath by yourself. It can be called to create cell, not to change it.
You can update your table by passing needed string to the first view via delegate, for example. And on the event (user sets the name) you can update all table and set needed names to cells.
Hard to say exactly what the problem is, but one possible solution might be this:
Make sure that in your cellForRowAtIndexPath you are initializing the cells like this:
// Create the Cell
static NSString *recordCell = #"pickerTableCell";
cell = [tableView dequeueReusableCellWithIdentifier:recordCell];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:recordCell];
}
I know this is primarily a memory solution, but might gelp here too.
Also, look through your code and check how you are determining which cell is renamed. You could be accidentally calling the rename on more than one cell without realizing it

Highlighting cell when selected

I have a tableView, and i can select multiple records. When i click more that 1 record the cell should get highlighted. i have attached my code below; What hapence now is that when i click on multiple records it higlights, but when i try to remove it (as in click the same row again), a different cell gets un-highlighted. Why is this ?
But if i replace the [cell setHighlighted:YES animated:YES/NO]; with [cell setAccessoryType:UITableViewCellAccessoryCheckmark]; everything works properly. How can i fix this ?
I have added code in the didSelectRowAtIndexPath
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell accessoryType] == UITableViewCellAccessoryNone) {
[cell setHighlighted:YES animated:YES];
}
else {
[cell setHighlighted:NO animated:YES];
}
You might want to use UITableViewCellAccessoryCheckmark, as it is intended for this purpose.
According to apple developer documentation for selecting more than one row you should use .
cell.accessoryType = UITableViewCellAccessoryCheckmark;
and for Deselect
cell.accessoryType = UITableViewCellAccessoryNone;
As others have stated, highlighting is not the preferred way to do this. Users want a consistent experience across apps, which is why the Human Interface Guidelines recommend using a checkmark to indicate row selection: http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/UIElementGuidelines/UIElementGuidelines.html#//apple_ref/doc/uid/TP40006556-CH13-SW42 (Table 7-1)
Aside from the UI issues being raised, the problem you are experiencing may be due to your table cells being reused, and retaining the highlighted state from the record that was previously displayed in that cell.
I suggest you keep a separate record of indexes/id's for those highlighted. You should then always check against this, rather than the state of the cell itself. (You can use NSArray or other collection class depending on your needs).
In tableView:cellForRowAtIndexPath: you should also check this array and set the highlighted state accordingly.

UITableView cell redraw causes text to overlap

I do following in cellForRowAtIndexPath
NSString *cellIdentifier = #"Cell";
LibraryCell *cell = (LibraryCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell != nil) {
[cellIdentifier release];
[self setItems:cell forRowAtIndexPath:indexPath];
return cell;
}
cell = [[[LibraryCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier] autorelease];
[self setItems:cell forRowAtIndexPath:indexPath];
return cell;
[self setItems:cell forRowAtIndexPath:indexPath]; changes only some UILabel's value inside the corresponding cell.
So now when I edit UITableView and delete let say the first row, the UILabel's value is no redrawn completly, i.e. the old value remains and new value is drawn overlapping the old one.
Why this happens and how to fix it ?
I guess you misunderstood the cell identifier concept.
It is only used to distinguish what you might call "stamps", used to print a cell's appearance on the screen. So you would most probably only need a single cell identifier.
It helps the system to cache instances of the "stamps". When cellForRowAtIndexPath is called, you only have to pick which kind of stamp you want to use. If you created an instance of the correct one before (i. e. you get one back when asking for it using the cell identifier string), you only need to change the label texts etc. and then return it. In real life this might be likened to one of those date stamps where you can change the date by turning the little knobs on the stamp. This is what you would do by assigning a new text to the label contained in the cell.
You instead seem to be creating a stamp for each index in your model by concatenating the string value, effectively creating as many instances as there are rows in your model. Apart from being unnecessary it might also cause memory pressure and stuttering, because it counteracts all sorts of optimizations the UITableView has.
I recommend you read up on Apple's documentation or see iTunes U (here)
for the Stanford courses on iOS development. It gets explained very clearly there.
First of all, You should use the same name for your cellIdentifier
Please refer to the UITableView Class reference
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:
If you cannot get a reusable cell, then create it. After that update your cell.
The code should be like this
LibraryCell *cell = (LibraryCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
// create a new cell
...
}
// Update cell
...
return cell;
Actually I figured out ! The problem was coming from setItems:forIndextPath method.
It was creating UILabel locally and releasing it. So every time it was drawn over the last text text. Making the UILable instance variable solved the issue.
PS. The code originally was not written by me, I'm just fixing it :)

Reloading UITableViewCell on select

Okidoke. Here's my problem: I have a series of complex UITableViewCells set up to display stories from a news feed (yawn). What I want to happen, is for the cell background image and height to change on selection (as a means of marking that the story has been read).
Now, prior to setting up dequeueing, I was able to do this with a simple [self.tableView reloadData]. That seems to be a no-go with dequeued cells; reloading the table view does not redraw the cells to match their changed state.
I've tried reloadRowsAtIndex- and while this works - beautifully - for the first cell a user clicks on, it goes wonky after that point: sometimes the cell reloads correctly, sometimes not.
Obviously, each story is an NSMutableDictionary object. I'm using an NSNumber object to track whether or not a story has been read.
I would post the code, and I will if anyone asks, but I'm looking for a generic solution that could be implemented in any UITableViewController (share the love).
So, simply put: how does one reliably redraw complex cells on selection?
Try giving each cell a unique ID in order for dequeuing to work, your cells should be coming back with their changed states if you use a unique id for each cell, so 20 cells = 20 ids, hope this helps
Assuming you have the index path, you can access the cell and manipulate it directly:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// handle the selection...
UITableViewCell *cell = [tableView cellForRowAtIndexPath: indexPath];
if (nil != cell) {
//
// now update the cell to reflect the new state
//
}
}

Is there a better way to determine the right size for a UITableViewCell?

I have a UITableView cell that is going to have a variable size depending on it's content (potentially several lines of text).
SInce it appears that heightForRowAtIndexPath is called before I layout the cell, I just guess the correct height by calling [NSString sizeWithFont] on my text string. Is there a better way to set the height after I've laid out the text in the cell and have an idea of exactly what size it should be?
It's going to sound dumb, but ...uh... "layout your cell before you exit heightForRowAtIndexPath" ;)
Seriously, though -- the OS only ever calls this if it's going to be needed (as in: it's about to create the cell & display it on screen), so laying it out & getting ready to display is not wasted effort.
Note, you do not have to do your layout separately, logic-wise. Just make a call to your [self prepLayoutForCellAtIndex:index] within your heightForRowAtIndexPath routine.
If the data is static, you can create a height table and cache the info.
if (0 == heightTable[index]) {
heightTable[index] = [self prepLayoutForCellAtIndex:index];
}
return (heightTable[index]);
Heck, even if the data changes, you can either recalculate the table value in the method that changes the data, or clear to 0 so it gets recalculated the next time it's needed.
I use the following, usually:
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath {
UITableViewCell *cell = [self tableView: tableView cellForRowAtIndexPath: indexPath];
return cell.bounds.size.height;
}
Note that I use this for tables where I pre-cache a bunch of rows ahead of time, not for those with a LOT of cells. However, for things like Settings tables, where there are just a few rows, but most likely very differently sized, it works well. For larger tables, I do something along the lines of what Olie suggested.
If you look at SMS.app as example, Apple saves the row height of the cell in the SMS.app sqlite database.