I am currently working on update to an app that I didn't make myself.
In it, there is a highly customized table view that is used for horizontal scrolling through images with 3 images showing at once and enabled paging.
The issue is that sometimes they appear white and I think that is because they are returned by dequeueReusableCell while they are still visible. (So table view is reusing the cell that, because is still visible, shouldn't be reused.)
Since there is usually not very many cells in that table, I tried with a workaround that alloc's and init's a new cell every single time instead of dequeuing an old one and so far it works fine (for a small table).
However, this is not a good solution and I want to do it the "right" way.
I don't know how is it decided whether cell should be put back to queue or not.
What should I do to stop cells from being queued for reuse?
If you really don't want the cells to be reused, do it the way you already did. It is not recommended to be not reusing UITableViewCells. The reusing-technique saves memory.
But when you tableView is not highly memory-expensive, do it like this. It is the way not "disable" reusing.
It sounds like it's because the tableView is rotated by 90° to achieve horizontal scrolling. So iOS thinks that the cell which got scrolled an amount out x pixels and must be located offscreen and can be reused. This is what I presume.
When your update addresses iOS 6.0 and later I'd recommend switching to UICollectionView which is very similar to UITableView but has the ability of totally customized flow layouts (this is the term you'd google for).
When my presumption is correct, another possible solution could be to use two reusable IDs and alternate them so that a cell got enough "space" to scroll:
if([indexPath row] % 2 == 0) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifierOne];
}
else {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifierTwo];
}
But I REALLY don't now if I'm right with this guess :)
Related
I have 180 UILabels (subviews of UITableViewCells) in an iPad app with 155 width X 155 height for each UILabel, and each one contains a big amount of Unicode text (Arabic language), when I scroll down the TableView it hangs for 1 second and then keeps scrolling normally, this happens with every scroll attempt by the user and this is tested on iPAD2 device.
however, when I changed the text to English language (also big amount of English text), the TableView does not hang and scrolls normally.
anyone got an idea on how to solve this issue with Unicode text ?
thank you so much in advance.
EDIT:
the code is large to fit here, so in brief, I create each UILabel with a loop like this: [[[UILabel alloc] initWithFrame:CGRectZero] autorelease]; in cellForRowAtIndexPath method, then play with the frame later in the same method according to interface orientation, after that I add each UILabel to the cell like this: [cell.contentView addSubView:myLabel]; . each cell contains 4 of these 'UILabels', so I have a total of 45 cells, nothing more, straight forward and simple code.
The use of unicode shouldn't be the problem here, as it will render at similar speeds to any other text.
There are possibly a few issues that are slowing down your code. First of all, you should attempt to use UITableView's native cell reuse, add the labels to the UITableViewCell and then dequeueWithResusableIdentifier them. You should only generate your labels when that method returns nil and you have to create a new UITableViewCell (it's unclear from the original question if you do this already).
One other thing you can do after this to make sure as many of your views are opaque as possible to speed up compositing. Instruments includes an option to tint non-opaque views to make this easier.
There are many ways you can optimize your code:
One check if your app is not leaking. Proper release of labels.
Use reusability of cells. I dont know if you are using that or not.
Since every time you scroll your cellForRowAtIndexPath delegate method is called.
In case you dont know about reusability try this link.
I have a UITableView. each row is heavy object with videos, images etc.
When user scrolls this view how can I release the memory of not visible rows and load the current visible rows?
I assume you're talking about releasing memory that's used by the images and videos of your row, and not the row itself.
In your tableview delegate,
-(void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView
tells you when the tableview scrolling has stopped.
[myTableView indexPathsForVisibleRows]
gives you an array of what is visible.
If your row is not in this array, it is not visible, and you can do your image/video cleanup on it.
Are you recycling UITableViewCells as per Apple's recommendations? If not, you MUST read Apple's docs. Inside the cellForRowAtIndexPath: delegate you should have something [customCell setMediaObjects:]. Inside your customCell class you can release all the previous mediaObjects from memory.
As others have said, you should make sure you are recycling cells properly, and not destroying things you would need to recreate anyway when the cell is reused.
But, you may want to release other assets that the cell or its views are retaining. Or if that cell has any pending download requests, for example, you may want to reset their priority or even cancel them when the cell is offscreen.
I think the cleanest way to do this is to just override -[UITableViewCell prepareForReuse]
This is called when the cell is put back into the reuse queue. If the user is moving up and down the table quickly, you may not want to clean the cell up the moment the cell is off the screen (by looking at indexPathsForVisibleRows, for example).
But when the cell is actually put back in the reuse queue, that is a good time to do that work since you know that cell won't appear again on screen until you dequeue and configure it again.
A Closer Look at Table-View Cells - Apple Documentation
When you call dequeueReusableCellWithIdentifier first 10 (just ten cells can be shown at screen at one moment) cells will be created, then they will be just loaded and configured for showing.
So, cells are not released.
I use QuartzCore to add rounded corners to my UIImageView's within the cells of my UITableView
This is the code that I use:
fooImageView.layer.cornerRadius = 9.0;
fooImageView.layer.masksToBounds = YES;
fooImageView.layer.borderWidth = 1.0;
The problem is that when I add this code. The table cells movement is slowed down dramatically. I'm just wondering whether there are other alternatives to make the user experience much faster and to increase performance when scrolling a table view cell using this technique?
I see a lot of applications (most Twitter apps) that have no performance decrease when having rounded corners applied to images within their cells. Just wondering how they overcome the "sluggishness"?
Thanks for your help.
The first thing I would try doing is setting:
fooImageView.layer.shouldRasterize = YES;
This renders the rounded corner effect as a bitmap. I had some similar issues when using CALayer effects on views in a UIScrollView a while back, and this setting drastically improved performance.
Don't forget to set
fooImageView.layer.rasterizationScale = [[UIScreen mainScreen] scale];
to prevent pixelation (rasterization at the wrong resolution for the device).
there are 3 main techniques for improving UITableView performance that I use:
Always reuse cells, use the
dequeuereusablecellwithidentifier
when creating new cells. This
prevents the overhead of the OS
creating and destroying lots of
objects when scrolling fast.
Collapse the view hierarchy of the
cell. Instead of having lots of
views and subviews, create a custom
view and do all your cell drawing in
the drawRect. Apps like Twitter use
this approach for super fast cell drawing.
Ensure your images are opaque. You can do this by ensuring all image assets don't have alpha channels baked into them and by setting the layer's opaque property to YES.
Examples:
In the cellForRowAtIndexPath (the table identifier string simply creates a reference to cells that are the same type and can be anything you like):
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
// Create a new cell if necessary
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier] autorelease];
}
Check out the following link for examples of improving performance of UITableViews: http://developer.apple.com/library/ios/#samplecode/TableViewSuite/Introduction/Intro.html%23//apple_ref/doc/uid/DTS40007318-Intro-DontLinkElementID_2
Hope this helps,
Dave
You could do some masking. Overlaying the images with a mask-image that has a rounded corners square cut out from it and it will work like a charm.
Also be sure to use reuseCellIdentifier otherwise the table will lag if it gets even a little complex.
Short answer: set cells opaque and draw them yourself.
Follow the advice by StuDave and Magic Bullet, and see also Fast Scrolling in Tweetie with UITableView by the author of the official Twitter client ot learn how to do cell drawing. It's a simple and clear example project.
Beyond solving this specific issue, you should read UITableView construction, drawing and management (revisited) by Matt Gallagher to learn how to write custom table controllers and cells. This not only improves the performance of your code, it lets you do things which are not possible with the standard classes from Apple. Basically you will create an UIViewController that replicates key methods of the UITableViewController.
In my case it added endless subviews and the table view slowed down dramatically exactly as you said. I added this logic in willDisplayCell to fix the problem:
if cell.contentView.subviews.count < 3 /* elements in cell + subviews */ {
cell.contentView.addSubview(subView)
cell.contentView.sendSubviewToBack(subView)
}
I've started implementing a UIScrollView that will contain many thumbnail-sized pictures and will scroll only horizontally. For this, I keep a limited number of UIImageViews created and remove/add them to the UIScrollView as the user scrolls it.
The problem is I need to find a way to optimize it as scrolling sometimes gets sluggish. Maybe it's the adding/removing from the view, I don't know.
I figure this is a common component that might have been implemented more than once, but I couldn't find any library that featured something like this. If there is something ready available, I wouldn't need to spend many hours fine tuning or figuring out how to improve my component.
This is different from the question that has been asked here many times: I don't want it to behave like the photos app. I want many pictures to be visible at a time and to scroll them smoothly, without "hard pages".
So, anyone know of a component which does something similar to this?
I managed to do something similar by using a rotated UITableView instead:
UITableView *tableView = [[UITableView alloc] initWithFrame:...];
tableView.transform = CGAffineTransformMakeRotation( -M_PI/2 );
You can then configure your UITableViewCells to display the images. You can also rotate the UITableViewCell contentsView.
I made a two dimensional scrolling component called DTGridView. You can use it with just the one row to make a purely horizontal scroll view. It has an API much like UITableView, where you have a dataSource and a delegate to tell it how many rows/columns etc and to handle touch events for the cells.
It also uses a method of cell reuse like UITableView does to save on memory. If you aren't using cell reuse on table views, you should be. :)
In my app UItableView with custom cells, cells with image, but in some cells has not image.
In start the place without image is white. After scrolling table in that places appears others picture. Please help to fix this problem.
although your answer is rendering a working solution, I think it is not the correct way to deal with this problem.
Imagine an NSArray with a 1,000 NSStrings in it that you want to display using a table. By showing them in a cell with a unique id for that NSString, you are basically creating a 1,000 cells! This would slow down your app. The whole idea is that cells are reused so that only 1-2 more than displayed are created.
So the correct solution: deal with it.
reuse a cell by having a unique id just for that class
reset/renew content of the cell yourself, assume dirty content
ps watch the Stanford iPhone class on tables, number 8 (around 18:50), a guy from Apple explains all this.
http://www.stanford.edu/class/cs193p/cgi-bin/index.php
Your problem here is due to the way your are using the cell queue in the UITableView, I think you are not giving each one of your cells a unique cell identifier, because of this you are experiencing that pictures swap from one cell to another.