How to Render large size documents in iOS?
Asked Answered
F

3

16

I am working on a Reader Project, currently I am parsing the XML file and converted as an attributed string and I render it in CoreText (Used apple Sample Code).

The XML file size is above 6 MB. The texts are rendered correctly, but I can't render the images and Tables (like html tables).

At the same time I need to manage the performance. I have tried UITextView also, but it only displays quarter amount of texts only, after that the text disappears.

Is there any other technology to render texts, images, and tables?

P.S - The Client doesn't want UIWebView.

Fultz answered 13/4, 2015 at 6:23 Comment(4)
Have you checked this library github.com/nicklockwood/XMLDictionary or this github.com/mattt/OnoUncut
@MustafaIbrahim It's Just an XML parser. I don't have any problem on parsing. I am using NSXMLParser. The problem is rendering in a view.Fultz
Can you be sure that there will not be text next to the image or table and everything will be vertically ordered?Dimerous
Even if the client doesn't want UIWebView (wonder why) it's the best solution for your needs! I use it to display huge amounts of text and data with a memory footprint 20 times lower than an UITextView.Owing
P
3

When working on such large files, you may display data in several times. Here are several solutions:

  • Paginate your display by page : split your file into 10 parts (let's say, that's an example) and display with first part in a UITextView. Add two UIButton instances so that the reader can switch page. On page change, load the first/next part into your UITextView. This will not be particularly unfamiliar to users because you're reproducing the natural way they read an e-book. To determine in how many parts you should split your data, keep in eye that the user doesn't want to switch page continuously, you must adjust this with attention.

enter image description here

  • Paginate your display "smoothly": you paginate by page as explained above, but you will always deal with two UITextView embedded in a ScrollView. In the same manner than iOS reuses cells in a UITableView and load cell data on-demand (lazy-loading), implement this reusable mechanism with two UITextView instances - to go quickly, you can try implementing the mechanism with a standard UITableView.

Hope this helps!

Pit answered 15/4, 2015 at 13:26 Comment(9)
The client asks long smooth scrolling. This method is not suitable for my projectFultz
Can you provide any example on this? I searched over the net, didn't find any resourcesFultz
Can you provide me with a large file that is equivalent (in size) to the one you need to display? (lipsum.com can help you)Pit
It just creates 150 paragraphs, I have 10 times larger fileFultz
Working on it, I generated 150 paragraphs and then copied-pasted it 4 times!Pit
Please find the source code here: github.com/fiftydegrees/LargeTextFieldDisplay - you just have to adjust the buffer chunk (10 for the example) and process the height for each cell (I added comment).Pit
I am sorry, It's not working. It's not a best solution for my project :(Fultz
1. It's too slow for very large size document. 2. It lags every time loading next buffer. 3. I Can't create buffer for my large size documentFultz
Actually the way I suggested is just a hack to avoid re-thinking your document structure. At this point, you should seriously consider tell your customer to allow another experience (page loading) or reducing file size...Pit
D
0

UIScrollView is probably the only possibility. Divide your document into parts and place into UIScrollView appropriate subViews of classes UITextView, UIImageView and UITableView. To lower memory impact, leave placed only those subViews that are actually visible.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    [self removeSubViews];
    [self addSubViews];
}

- (void)removeSubViews {
    for (UIView *subView in documentScrollView.subviews) {
        [subView removeFromSuperview];
    }
}

- (void)addSubViews {
    NSArray* visibleSubViews = [self getAllSubViewsThatAreVisible];
    for (UIView *subView in visibleSubViews) {
        [documentScrollView addSubview:subView];
    }
}

- (NSArray*)getAllSubViewsThatAreVisible {
    NSMutableArray* arrayOfSubViews = [[NSMutableArray alloc] init];
    NSArray* arrayOfVisibleComponents = [self getAllVisibleComponents];
    for (NSDictionary *component in arrayOfVisibleComponents) {
        //there you have to create new UITableView, UITextView, or UIImageView according to what is needed and put this new component into arrayOfSubViews
    }
    return arrayOfSubViews;
}

- (NSArray*)getAllVisibleComponents {
//this is hard to tell how it should be written as I do not know your data. Lets assume, that you have an array of NSDictionary objects. Check all objects in this array, whether they can be visible or not. You shall know their future coordinates in scrollView, while in scrollView, you get visible part by usig property named contentOffset, which will give you top left corner coordinate and by using also property frame.size, you get whole visible rectangle
}

After doing this and testing it, you can optimize it by not removing all subViews and leaving there those that are still visible. Second optimization would be dividing array of compoents according to Y coordinate, so you will not have to iterate whole huge array always. Third optimization can be, that you will not redraw after every small scroll, but will place even some components that are not actually visible, but are close to visible area and after scroll first check whether there is redrawing needed.

Dimerous answered 15/4, 2015 at 13:15 Comment(9)
My document is in XML format, and its too large. If I create SubViews for each of them the app will be crashed by memory pressure. We can show all in UITextViewFultz
Is adding subViews to UITextView (now needed only UITableViews and UIImageViews) a possible way?Dimerous
Rendering a large text causes the slow in app speed. My file will have more than 4300000 Lines.Fultz
And to use UIScrollView while placing only subViews that are visible and removing them after scrolling? This might be slow, but it should be expectable for a huge size documents.Dimerous
Yes, It may be a possible solution. But no resource to implement this method. I am tried after searching for thatFultz
On scrollViewDidScroll check which subViews shall be visible and place them in, while removing all that were placed before and are no longer visible.Dimerous
I am new to iOS Development, I understood what you trying to say. but I don't have any idea to how to start this?Fultz
Why reinvent the wheel? A UITableView is a scrollview that knows how to fetch/unload its onscreen/offscreen views (cells).Furlough
I have been thinking about that possibility. It can be made, but only if all things in document will be vertically ordered. Otherwise, it will be quite complicated to code, although not impossible (if there will be for example text next to a column of few images). That is the reason for my question in comment under question.Dimerous
F
0

You haven't elaborated on the structure of the document encoded in your XML file. It could be very elaborate with HTML-like hierarchical structure or it could be simple - linear paragraphs of text interspersed with images and tables.

Assuming the latter I like the approaches by _sweepy and Reconquistador. But I might try using a UITableView and create cell types for each document construct - paragraph, image, table. Paragraph and image would be straightforward to implement using UILabel and UIImage views to render the content. Tables might be harder but I would likely leverage a UIWebView or WKWebView to render the table only.

You would need to parse your XML into some structure or backing store where you could lookup a given document construct by linear index. Assuming a huge document I'd lean towards SQLite or CoreData.

Scrolling would be smooth. The table would load cells as they became visible and unload them as they scrolled offscreen.

Furlough answered 21/4, 2015 at 22:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.