Bi-directional progressive loading in tabulator - infinite-scroll

I'm looking to load a large quantity of data within tabulator and running into performance issues. Having only the small subset of records that are visible loaded would be ideal.
Reading through the documentation I could use progressive loading with an ajaxurl to load data as the user scrolls down the table with ajaxProgressiveLoad set to scroll.
Is there any way to discard the data that the user has scrolled past to keep the memory footprint low. This would also require the ability to reload it if they scroll upwards. Essentially a bidirectional infinite scroll.
I presume this could be implemented by modifying the existing ajax module, would appreciate any pointers in the right direction.

Related

Is it a good idea to add uiwebviews in table cells?

I have several local html files and I want to show them in a table with static(for now) cells.
Each UIWebView would have a different height (I dont want to have any scrolls in the UIWebView) so obviously each cell has a different height. Most of the comments i read discourage the usage of UIWebView in table cells. What do you think : is this applicable ? will it be slow and need time to load?
UIWebview in tableview cells will affect the performance for sure. To display Html content in tableview cells you can use NSAttributedString.
I used a UIWebView in an app to display content coming from the web as rows in a table view.
I know that doing that is discouraged, due to the high memory use of UIWebView, but in my case it was not only a matter of displaying rich text: I had to display HTML loaded from the web, so I give that option a try. In short, I tried it and it worked fine.
The app got memory warnings from time to time, but it was also able to recover memory effectively and run unaffected even on an ipod touch (just 256MB of memory). Performance was possibly affected, but due to the fact that the app was doing just that (loading text from the web and displaying it in the table), the app was perfectly responsive.
One important notice: pages were pretty simple, just text, and each table did not contain more than 15 elements. Furthermore, one thing you have to consider is that the UIWebView introduces a small delay in the rendering, so you will have to deal with it and accept it in your app (there is no way to get rid of it that I know of).
In a later project, I used a different approach: using just one UIWebView and creating the table using HTML/js inside of it. Well, it also worked, but I could not see any big improvement as to peak memory usage nor performance (I checked with instruments).
This is just my experience, I am not trying to say that this will work or that is good practice to do. In any case, I hope it helps.

UIScrollView Lazy Loading Strategy With a Twist

I have a horizontally scrolling UIScrollview with paging enabled. Each page represents a data feed. Each data feed consumes a fairly large amount of memory including text and images displayed in a UITableView. Since the user can have an unlimited amount of data feeds, I need to lazy load them to prevent maxing out my memory usage. My thought is to keep up to 5 data feeds in memory at any given point, and release anything outside of that range. My initial take is to keep the page in the viewport in memory, and the 2 pages to either side of it. This way when the user scrolls, the next sequential page will always be in memory and will display quickly.
Here is my problem:
We also need to support a scenario where a user can skip to a specific data feed, possibly 10 or more pages to the right or left, which throws my entire lazy loading scheme out the window.
Might there be a better strategy to support this scenario?
Yes, what you can do is create an outer scroll view, which houses individual cells akin to a tableview. In this respect, the cells have a content view which you can place your data, let's just assume you know how to do that since it seems you do.
Once you have this architecture in your mind, it becomes fairly clear: You can, knowing the width of your cells, and the size of the screen, some simple math can tell you how many you have on screen, and you can add one to the left or right so you're preloading some data for when the user scrolls.
This will say, give you the ability to have in memory, at most 5 feeds, if 3 are visible, at the start or end of the content view in the scrollview, 4 feeds, regardless of whether or not you have a billion feeds.
One critical part of this is cell reuse. You maintain a couple NSSets, one for recycled cells, and one for visible cells. Add items that have gone off screen to the recycled cells, dequeue items from recycled cells when setting up the cell, as to save additional memory allocations, which can be expensive. Just remember, using this strategy, you are still subjective to the same caveats as a UITableView with respect to cell reuse.
I'm plugging some software I wrote here, so forgive me for that, but I'm doing so as an example of what I'm talking about if you get stuck implementing what I discussed here, it's available here for your perusal.
One final note. To support skipping of cells, it's just simple math again to adjust the point in the scrollview you are at. The action for this can be done with a gesture, though now we're talking a pan gesture recognizer, with some specific properties that will be specific to your application, as an example. Or you can use buttons if you really must. Just ensure you know how to calculate your offsets to your cells, and scroll to that point. You'll be fine.
It's hard to give accurate advice with the information provided in the question. So I will just present a few thoughts I got when reading the question.
Does it take long to download a feed? Would it be possible to just download a few item (a screenful) to get the first few items showing right away? Perhaps lazy load the images if possible.
Have you considered caching the feed data on disk? That way you can present some data right away and then update the feed as new data gets downloaded.
Since each page is a feed view, would the user just scroll past a feed without looking at it? Do you really need to load 2 views on each side or can you get away with just 1 view on each side.
I don't think your lazy loading scheme stops working just because the user can skip directly to any page. You would have to start loading the data for that page when it is selected but by using a disk cache or downloading a small sample could make the app feel faster. I also think that using some kind of animation to animate to the selected page could buy you a little time.
Here is my problem: We also need to support a scenario where a user can skip to a specific data feed, possibly 10 or more pages to the right or left, which throws my entire lazy loading scheme out the window.
Then you need to fix your data structure. I wrote pretty much exactly this (a UITableView-like paging scroll view) and it works fine (there are some reloading quirks, but hey...).
Keep track of which pages you've loaded. I used a ring-buffer-alike modulo 8 and spent a while getting the code right; it's probably a lot easier to just use an NSDictionary with NSNumber keys and UIView values. This means when you change from page 1 to 10, you can still tell that the loaded views are for pages 1, 2, and 3, and drop them.
Load the required pages in -layoutSubviews. I would load 1 or 3; 5 is probably too many (but you need to load at least 2 if you're between pages).
Load 3 (one to either side) in -scrollViewDidScroll:. This is so that when you scroll from page 1 to 2, it doesn't try to load page 4 (which hasn't been loaded yet).
Load 5 (two to either side) in –scrollViewDidEndDragging:willDecelerate: if willDecelerate is NO, –scrollViewDidEndDecelerating:, –scrollViewDidScrollToTop:, and –scrollViewDidEndScrollingAnimation:. The idea is that the animation's over, so you can load the extra views without the user perceiving lag.
Possibly load 5 in –scrollViewWillBeginDragging:, to make sure that page 3 is loaded if you're currently on page 1.
I decided to do "two pages either side" because when you flick from page 1 to page 2, it often shows a pixel-wide sliver of page 3 when it bounces. This can be avoided with scroll view insets, but we didn't think of that at the time (oops). There's otherwise not that much of a reason to choose 5 over 3.
It's a bit of work to get right, but otherwise seems to work flawlessly.

iPhone: Reading many images quickly

I've got an app I'm working on where we handle a LOT of images at once in a scrollview. (Here's how it looks, each blue block being in image on a scrollview expanding to the right: http://i.stack.imgur.com/o7lFx.png) So to be able to handle the large strain doing this puts on memory. So I've implemented a bunch of techniques such as reusing imageviews etc which have all worked quite successfully in keeping my memory usage down. Another thing I do is instead of keeping the actual image in memory (which I of course couldn't do for all of them because that would run out of memory very quickly) I only keep the image's filepath in memory and then read the image when the user scrolls to an area of the scroll view near that image. However, although this is memory efficient, it's causing a LOT of lag in the scrollview because of the fact that it has to constantly read images from the disk. I can't think of a good solution on how to fix this. Basically right now the app draws to the screen only the visible uiimageviews and while the user scrolls the app will look to see if it can dequeue another imageview so it doesn't have to allocate another one and at that point it reads the image into memory, but as I said it's causing the scrolling action to be very slow. Any ideas on a strategy to use to fix this? Does anyone know what the native photos app does to handle this kind of thing? Thanks so much!
I can suggest you a simple solution to balance both the memory and the computer processing. You only keep small images like thumbnails in memory and only keep about 20 of them. One project that I am doing, I keep 20 thumbnail images (100 x 100) recently accessed, which doesn't cost a lot of memory. I believe that it costs about 200 kb all the time but comparing to a general available memory. I think it is good enough.
It also depends on your use case : if user scroll really fast and you don't know when will they go. You can have even smaller images than the thumnail and when you show it on the UIImageView, you resize it to fit. When user stops scrolling for a while. You can start loading bigger images and then you have a nicer images. User may not even notice about the process
I don't think there is a solution that can be fast and using as less memory as possible. Because we have memory, maybe not big but have enough if we use it smartly.
Slow scrolling performance might mean that you're blocking the main thread while loading images. In that case, the scrolling animation won't continue until the images are loaded, which would indeed cause pretty choppy scrolling performance.
It would be better to lazily load requested images in the background, while the main thread continues to handle the scrolling animation. A library that provides this functionality (among other things) is the 'three20' library. See the Tidbits document, and scroll down to the bottom where the 'TTImageView' class is described.
I had a similar issue with a PDF viewer, The recommended way to do this is to have as low a res image as you can get away with and if you are allowing the user to blow the image up/zoom, then have two versions or three versions of that image increasing the res as you go.
Put as much code as you can get away with in the didDecelerate method (like loading in higher res images like vodkhang talks about), rather than processing loads in didScroll. Recycle Views out of scope as you have said. and beware of autoreleased Context based Image Creation functions.
Load images in on background threads intelligently (based on the scrollView Offset position and zoom level), and think about using CALayer/Tiled Layer drawing for larger images.
Three20 (an open source iOs lib) has a great Photo Viewer that can be subclassed, it has thumbnail navigation, large image paging, caching and gestures right out of the box.

Appropriate control for page like swiping

I currently have a UIScrollView which has a content size equal to about 50 pages, each one the size of the application view.
I have implemented scrolling by using paging and at all time keep current, previous and next page in memory, while the rest are created when required, e.g. when one swipes forward, the old 'previous' view is released and a new 'next' view is loaded.
The new pages are loaded and old released when 'scrollViewDidEndDeaccelerate' is called.
The disadvantage with this is of course that the page needs to settle completely before a new page swipe may begin.
Is there a more efficient way of doing this with a different type of control? UITableView?
I am looking for solutions with other type of controls - not UIScrollView implementations with e.g. placeholder images and loading high res on demand.
Sounds like you are on the right track as predictive caching is about the only idea I can offer...which you are doing. Maybe checking available memory and loading to a certain percentage of that might help, with caveat that you monitor the low memory warning and dump items that are the farthest from the current view location.

Should I use Table View or one long chunk of HTML for iPhone?

I'm making an application for the iPhone. Essentially it'll be a guide of sorts, and all the generated information will be in one long window. Each block of information can have a 'link' in it to generate another block of connected information (for example a block about Wallace could link to a block about Gromit) that would appear at the top.
For example, at the start 1 block of data:
Wallace: Owner of Gromit
would become 2 blocks (on clicking Gromit):
Gromit: Wallace's Dog
Wallace:Owner of Gromit
Each block would also have the ability to be added to favorites list by clicking an icon. The text would need to be laid out with HTML and each block may be of a different length. A search on a different could also add a block to the top.
I'm OK with objects in 'easy' languages like PHP, but am basically new to iPhone and Cocoa, and I want to start off with the right approach here. A Table and cells looks like the correct approach, but is there any advantage of doing it as a long list (like I might do on a web version) or are there any restrictions in the way cells can hold/layout information that will cause me trouble down the line.
I believe this approach is popular for dictionaries.
I'm committed to doing it the way with a single scroll for a couple of reasons. The main one is that I want the user to be able to scroll instantly back to entries they've looked at before. i.e. the single view essentially represents a history of the data they've looked at. (if it's a lot stuff can drop off the end). Each entry will be very short but there will be a lot in total. So if the user has looked at
Wallace
Gromit
The Wrong Trousers
Cheese
Penguin
And they are not looking at Wallace, a quick half second scroll takes them back to 'penguin'.
Hierarchy is the way to go on the iPhone.
Remember that the iPhone has a small screen and that users can only see a very small amount of information at anyone time. (One interface expert compared it to driving while peering down a two inch pipe with one eye.) Users can easily get lost scrolling up and down a very long list even if it has index. (That's assuming your information can be easily indexed in a form that users will instantly recognize.) It's usually easier for users to click through several views with the data in each view getting more and more specific with each level. In addition, so many apps use this hierarchal system that your users will be used to it and expect it.
System wise, its easier for the iPhone to display just one level of hierarchy at a time so your app feels more responsive. The hardware doesn't to maintain all the data in memory but just the data it needs to immediately display.
If I understand you data model correctly, you would be best off with a hierarchy of two tables and a detail view. The first table would have an list of letters A-Z. The second table would be list of all records starting with that letter. The third would be a detail view showing links to that record. So, to see the example in the OP, a user would select W-->Wallace-->(Detail) Gromit.
Edit01:
I think you should do a test scroll of either a very long web page or UIScrollView and see how it affects performance and usability. I would caution you that layouts that seem perfectly usable and fast on laptop or desktop hardware become unusable and slow on mobiles with their weaker processors and much smaller screens. It's much more difficult to do " a quick half second scroll" back to a specific point on a long page on a mobile than on a larger screen.
You do have the option of creating a outline-like table view that inserts new indented cells as needed. I still think hierarchy is the quickest and most usable layout on a mobile.