In my iPad application, I've made a segmented control and one segment of which -when clicked- displays a long list (about 300) with images and labels from the local SQLite database. This is taking a lot of time to load and puts the app activity to halt while it's loading all of it from the database.
Although I've applied an activity indicator for the time being, but that looks very shoddy. Can anyone tell me how to apply Lazy Loading in a way that When the button is clicked to open that view, instead of loading all the content at once, it fetches only the content that's displayed on the content initially (about 9 images with lablels).
Thanks in advance.
You should implement paging on the list. Load first 25 item and then add button ("Next 25") on tableFooterView, which will load another 25.
If you use a UITableView, you might have a better chance.
A UITableViewCell loads cells one at a time(gives you the index of the item it is trying to load), so if you use a table view, it will only load the number of items that it needs to display. You tell it how many items there are, how tall they are, etc.
It also reuses cells, so it gives a lot better performance than creating 300 different views in memory at a time.
A UIScrollView doesn't know about your "items", so it lets you push as many items as you want into a view, and then adds a scroll bar. No optimization here for memory usage, or database access.
Related
I have a large number of custom views (all the same class) in a scroll view and I'm frequently getting memory warnings. Is it possible to somehow only allow a view to draw when it's about to be displayed and then release that view when it's no longer being displayed (i.e. it's been scrolled past) to reduce memory usage?
If you want to reduce the memory usage of views within a scroll view a better approach consist to define a set of views and reuse them during the scrolling process by putting them in a queue. This requires some work. I don't know how you want to layout your views but if it is a in a grid you can find some third parties libraries that does just that. One of the most famous one is called GMGridView it worth taking a look to understand how the views are being queued.
In the end I managed to solve this issue by removing all the unneeded sub views when one sub view was selected to be viewed in full and then adding them again afterwards because this isn't a hugely costly process.
Should one "lock" a UITableView whilst it is updating somehow?
That is, during a data refresh for a UITableView (assuming it takes a few seconds), should one be somehow locking the view itself so that users can't click through on rows etc?
Just wondering what precautions (if any) a developer should take here.
Depends on the context. A common solution, when there’s no guarantee that the contents of the table will still be valid once the load completes, is to cover it with a semitransparent full-screen overlay view displaying an activity indicator or a progress bar. If you’re just loading new data, though—i.e. the old data in the table is still valid, like when you’re refreshing a news feed or similar—there shouldn’t be a need to lock anything.
Set the userInteraction to disabled.
When table is getting updated and its time consuming such as loading numbers of image using url or getting thumbnail of videos playlist or getting data from webservice etc then there is need to use lazy loading of content of in table view cell so there will be no effect of time consuming data in table view as it will be disaplayed when lazy loader has content of data without effecting tableView
can someone please clarify this: when a table cell scrolls off the screen, does it still reside in memory? The reason why I am asking this is, I had to use a tableview that has to handle too many cells.
when you scroll the table up, it loads next set of visible cells. At this point, i want to make sure , that all the cells thats been scrolled off, wont be added as a heap slowing the performance. Thanks,
If you queue the cells then each cell, as soon as it disappears from the screen (that is, it is scrolled up or down), is re-used for other new cells entering in the screen.
This means that if your screen can show no more than 7 cells at the moment, the memory taken for cell allocations will not be higher than the one needed for exactly 7 of them.
The advantage of this approach is memory saving but also performance improvement as you don't need to alloc/init the cells each time.
Of course this is valid if you appropriately autorelease cells when created, if you use the same queue identifier and of course it is independent on your way to manage the data you will insert in the queue (images, strings, ...)
I have a Nib file containing grouped table view and a cell. The cell is connected to UITableViewController through outlet. In cellForRowAtIndexPath I just return that cell and I can see a single cell in the table view. But when I change the row count of table to 2 and want to show the same cell, then I can see only one, it appears that the second cell is intended to be there, as the lower corners of the visible cell are not rounded, however, it's not there.
If I create a second cell object in nib file, second outlet and return it as second row, the it appears fine. My cell has identifier specified in IB.
Does it mean I can't re-use cell object for more than one row?
In the same way as you would need one instance of a UIButton for each visible button in your view, you will need one instance of your cell for each visible row.
The common pattern to manage this, is to ask the tableview for a previously instantiated cell that is no longer needed (dequeueReusableCellWithIdentifier:), and then return that cell. If the table view does not have any reusable cells, you have to instantiate a new one from your nib file.
There are many examples on this around the web, and you can also find some here at SO, ex in this answer.
I would recommend that you read through Apples TableView Programming Guide, which also contains a section on loading cells from nibs.
UPDATE:
An attempt on explaining the TableView and reuse of cells in a different way.
Lets say we have a large gallery with
old paintings. Thousands of paintings.
The gallery has just one display room,
though, and it has walls for just ten
paintings. The gallery manager has to
switch paintings now and then when the
visitors get bored and want to see
some new paintings.
Every displayed painting needs a
frame. Without a frame, it can't be
put on a wall. Frames are expensive to
make, and take up a lot of space. The
frame maker guy want have time nor
money to build the thousands of frames
needed.
He finds out that he want be needing
frames for all the paintings that is
not shown at the moment. He would only
need ten frames for the currently
displayed paintings. When the gallery
manager takes down a painting, the
frame maker stores the frame, and when
the gallery manager put up a new
painting and asks the frame maker for
a frame for it, the frame maker
returns the frame from the previous
painting again.
One day, the
needed-space-between-paintings-regulations
gets changed for no good reason. The
gallery manager is able to put up two
more pictures in the display room. He
picks two paintings from the store
room, and asks the frame maker for
frames. The frame maker has no spare
frames, and need to make two new
frames.
Now, lets say that the gallery is a TableView, and all the paintings are rows of data. The display room with space for ten visible paintings, is the screen, with space for ten visible rows. Each visible row would need a cell, just like each displayed painting would need a frame.
In the end, you shouldn't care that much about saving resources by reusing one cell. That's TableViews responsibility. It's an implementation detail of the TableView how many cells is needed and how it is used. The protocol defines how you can ask the TableView for an reusable cell, and the documentations states that you should. That should be enough. Demo projects shows that TableView can manage very large amounts of data. If your projects struggles with performance because of instantiating 10-20 cells from nib, you probably got some problems with your nib file or something. There are some discussions, though, about the performance of loading from nib versus building cells in code. It may be interesting to you.
I had some very weird behavior that sounds very much like what you are describing some time ago.
Eventually I found that the problem was that I had just added a table view cell to a xib which contains other items such as the parent table view and controller. What I had to do was create a seperate xib for each table view cell individually. I think the issue was that loading the table view cell from an incorrectly built xib was confusing the issue.
As Vegar said there are a lot of tutorials on how to do it.
I'm building an app (not necessarily a twitter client) and I'm trying to figure out how developers create the buttons above and below a table view where a user presses them to either reload newer data or reload older data into a table view. Does anyone know of any tutorials out there that does this or know of an easy way?
If you want fixed buttons, you can just make your table view not use the full screen and add the buttons in the space. If you want the buttons to scroll with the table view, you can add a header or footer view to the table and put your buttons inside that.
Check the Three20 project. I believe there's a tableview there that does that.
It's actually not that hard to add inline buttons to a tableview. First you check and see if there's actually more data to show. If so, you want to add 1 to the number of rows returned from the datasource. When asked to draw that last row you return a cell that contains "Press for more" caption as well as a hidden spinner instead of the standard cell that shows your normal data.
If the user presses that last button the table view handler turns on the spinner then fires off a network event. Once the network request completes the data is processed and added to the same tableview datasource that was used to draw the first table.
Now all you have to do is tell the tableview to reload itself and the new data will show up. If you want to limit the amount of data shown you can prune out N number of items from the head of the datasource before redrawing so the memory-use stays manageable.