Loading PDF into UIWebView - Anything faster? - iphone

I'm doing an application, which loads PDFs from an URL, but is there anything better then using UIWebView? Or any way of loading it page-by-page instead of loading the whole file at once?
I mean it does the job, but it takes 30seconds - 3 minutes to load a PDF on an iPhone 5 while standing NEXT to the router...
I can't imagine what would happen when I ran this code on an iPhone 4 with crappy internet...
Code which does the loading:
CatalogsWebViewController *webViewController = [[CatalogsWebViewController alloc] initWithNibName:#"CatalogsWebView" bundle:nil];
NSString *urlString = [[NSString alloc] initWithFormat:#"http://%#.s3.amazonaws.com/%#",kAmazonAWSBucketName,[catalogs objectAtIndex:indexPath.row]];
NSLog(#"%#",urlString);
webViewController.pdfRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
[self.navigationController pushViewController:webViewController animated:YES];
//Here self is webViewController, which got pushed into the navigation controller.
[self.webView loadRequest:self.pdfRequest];
Hum... it turns out, it's not due to the webView, it's cause it takes an immense time to download the file from the S3 bucket. When loading it from [NSBundle mainBundle], it does it it seconds.

As the problem comes from network connectivity, you should display a loading bar while downloading the PDF so the user understands what is going on. Then, upon download completion, save the PDF in the documents folder of your app if the user wants to reopen it later

Related

How to download things without display hanging?

Okay. So I'm creating this app and I'm really happy with it apart from one thing. It uses a lot of internet database checking etc. and every time it does this it hangs until it has finished, spoiling the fluidity of the interface. Is there anyway to avoid this? Download stuff happens when you click a button or sometimes just as a result of an NSTimer. I would love for the user to be able to go through the interface fluidly and the app to update the info when it gets there. IS there anyway to do this?
EDIT - Current Synchronous code:
This is to download a CSV file:
NSString *link=[[NSString alloc] initWithFormat:#"http://d.yimg.com/autoc.finance.yahoo.com/autoc?query=%#&callback=YAHOO.Finance.SymbolSuggest.ssCallback",timer.userInfo];
NSURL *url=[[NSURL alloc] initWithString:link];
NSData *dl=[[NSData alloc] initWithContentsOfURL:url];
NSString *str = [[NSString alloc] initWithData:dl encoding:NSUTF8StringEncoding];
This is to download a png file into a webView:
NSString *link=[[NSString alloc] initWithFormat:#"http://chart.finance.yahoo.com/z?s=%#&t=GOOG&q=m",self.Input.text];
url=[[NSURL alloc] initWithString:link];
[self.graph loadRequest:[NSURLRequest requestWithURL:url]];
It sounds like you're making synchronous requests. You shouldn't be doing that on the main thread. Your best option is probably to switch to asynchronous requests. You could make synchronous requests on a background thread, but that's more complicated and unnecessary in most situations.

UIWebView doesnot load pages properly in iPhone

I am new to iPhone,
I made ePub reader app, in which i am loading local .html page in my webview.
when i load my .html page it works properly but after some time it does not load properly. something unexpected things gets loads in my webview like html page's text color gets changes,backgorung color gets changes and images gets resizes and all several unexpected things occurs, when this things occurs at a same time when i click on button and on click when i call [webview reload] then everything again gets works fine.
Why this is occuring ?
I am creating webview in viewDidLoad
webView = [[UIWebView alloc] init];
webView.delegate = self;
[self addSubview:webView];
[webView release];
Any help will be appriciated.

UIWebView acts differnetly in app store version than dev version

I've got a problem with an app that works perfectly in the simulator as well as a physical iPhone 4 and an iPhone 3GS. The app was approved and is now in the App Store, but the distribution build downloaded from the App Store exhibits a bug not seen in the dev/release build.
This is a free app, but is supported by local advertising. When the app launches (or returns from background), the AppDelegate attempts to download some HTML from our ad server, and if successful, presents a modal view controller with a UIWebView and passes an NSData variable containing the HTML. In development/release builds, this works PERFECTLY; the app launches, and after a few seconds, a view slides up and shows the ad, which can be dismissed with a button.
However distribution build from the App Store is different. When the modal view controller slides up, the UIWebView never loads. Remember, I present the view controller ONLY if able to download the ad data -- otherwise, the view is never presented.
Thankfully I implemented a timer in the ad view controller which will cause the modal view to dismiss itself if the webViewDidFinishLoad never fires (in which the timer is invalidated), so at least app users aren't too annoyed. But it's still ugly to have an empty view controller slide up and then slide away for apparently no reason.
Here's the relevant methods in the AppDelegate:
- (void)launchAd
{
[NetworkActivity showFor:#"ad"];
if (!alreadyActive && [ServerCheck serverReachable:#"openx.freewave-wifi.com" hideAlert:YES])
{
alreadyActive = YES;
[self performSelectorInBackground:#selector(downloadAdData) withObject:nil];
}
[NetworkActivity hideFor:#"ad"];
}
- (void)downloadAdData
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *baseURL = #"http://appdata.freewave-wifi.com/ad/";
NSString *file = (IS_IPAD) ? #"ipad.php" : #"iphone.php";
NSURL *adURL = [NSURL URLWithString:[baseURL stringByAppendingString:file]];
adData = [[NSData alloc] initWithContentsOfURL:adURL];
[self performSelectorOnMainThread:#selector(presentAdModal) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)presentAdModal
{
if (adData)
{
AdViewController *adView = [[AdViewController alloc] initWithNibName:nil bundle:nil];
[adView setAdData:adData];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:adView];
[navController setModalPresentationStyle:UIModalPresentationFormSheet];
[navController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[tabBarController presentModalViewController:navController animated:YES];
[navController release], navController = nil;
[adView release], adView = nil;
}
else
LogError(#"Not presenting ad; unable to create data object.");
}
By the way, adData is defined in header with NSData *adData;
The AdViewController simply contains a UIWebView, which is loaded with
[webView loadData:adData MIMEType:#"text/html" textEncodingName:#"utf-8" baseURL:nil];
Again, this all works PERFECTLY, EVERY TIME with dev/release builds in simulator and physical devices -- just not on distribution build from app store. I have even converted the NSData to an NSString and barfed it out with NSLog() just to prove that the HTML was downloaded before presenting the AdView modally.
[sigh...]
EDIT 1: In case my original post was not clear, the webViewDidFinishLoad never gets called in distribution build (but it does in dev/release build).
EDIT 2: Also, just before I call
[webView loadData:adData MIMEType:#"text/html" textEncodingName:#"utf-8" baseURL:nil];
in the AdViewController, I added a temporary NSLog() and converted adData to NSString and logged it to the console, and the HTML was there. So, the UIWebView just refuses to load the NSData?
HOLY COW. I figure it out.
Okay, before I say what I found, I did want to correct my own original wording: the modal ad has never worked in the simulator, but always on devices. I know the simulator can have its quirks, so I never thought anything of it, especially since it always worked on the devices. I know this is an important detail that was missing for this discussion, but it's been a couple of weeks since I worked on this project, and I'd forgotten all about it until today.
Now then... While tinkering with things, I noticed the AdView.xib was not in my project file list. I expanded a few folders thinking maybe it was accidentally dragged into one of them, but it was not listed at all. This really has me puzzled, though -- Xcode NEVER complained about a missing resource (no warnings or errors; always a perfect compile).
So, I navigated to the physical location and added the AdView.xib into the project. Now, the modal ad is displayed in the simulator, which is a first. I figure that since now the app works correctly in the simulator, it should work fine in the distribution build (odd correlation to make, but it's all I got until my update hits the App Store).
Obviously, I'll be submitting an update, so I won't accept my own answer until after the update hits the App Store (assuming I have actually fixed it).
Ok, this is an extremely long shot, but perhaps worth considering.
The docs for NSData state that with regards to initWithContentsOfURL "The returned object might be different than the original receiver." So, if it was a different object, and one which was in fact autoreleased, consider this line in your code:
adData = [[NSData alloc] initWithContentsOfURL:adURL];
This won't add a retain count for adData -- you didn't write self.adData = or similar. So, bearing in mind the scenario mentioned whereby the returned NSData was autoreleased: your method downloadAdData wraps its content in an NSAutoreleasePool. This is correct practice. However, that might result in adData being released BEFORE presentAdModal is called on the main thread. So...
In presentAdModal you just check that adData isn't nil -- but it can be not nil, and still have been deallocated from memory at that point by your NSAutoreleasePool -- hence, you would in this situation trigger the "show web view" code, but be attempting to load an NSData object that had been trashed. Which probably would contain complete garbage, hence no successful "web view loaded" call.
As I said, a long shot, but the ony thing that jumps out at me at this point.
UPDATE:
A completely different cause of your problem might be this:
Your test environment (i.e. non App-Store builds) is making requests from a certain part of the internet (i.e. your office) which has permission to access the web server containing ads, due to either IP blocking or whatever network setup there is, whereas your App Store release builds are attempting to access the ad server from parts of the internet which are forbidden. Again, probably not the case, but worth mentioning.

Save history of UIWebView and reload it

I have a view with a subview of UIWebView and the view is obviously managed by a view controller. Say, I browse with this UIWebView for sometime and then navigate to a different view managed by a different view controller and then return to the UIWebView view. It will load the parent URL and not the one where I had left it. How can I load the URL where I had browsed till along with the history i.e., ability to go back to the parent URL from the URL where I had switched views. The code might help.
NSString *string = [[NSString alloc] initWithString:#"http://www.google.com"];
NSURL *url =[[NSURL alloc] initWithString:string];
NSURLRequest *aRequest = [[NSURLRequest alloc] initWithURL:url];
[webView loadRequest:aRequest];
When we come back to this web view, it will load 'url' again. But, I want it to load the url where the UIWebView was last at.
Thanks.
It is really simple. On viewWillDisappear method, save the current URL of the webView.Request, on next launch, try to see if it has value and load the one existing, otherwise, load the default "google.com". Hope this helps.

PDF in webview performance

I am using the following (simple) code to load a PDF from the documents folder in my app into a UIWebView. The performance is very poor. I tried loading the same PDF from the web via Safari and the performance was great. Does anyone have any ideas? (this viewController is being presented as a modalViewController).
- firstView.m
InfoViewController *mcontroller = [[InfoViewController alloc] init];
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *pathToPDF = [NSString stringWithFormat:#"%#/myPDF.PDF",docsPath];
NSURL *targetURL = [NSURL fileURLWithPath:pathToPDF];
mcontroller.urlToFile = targetURL;
[self presentModalViewController:mcontroller animated:YES];
modalViewController.m -
- (void)viewDidLoad {
[super viewDidLoad];
NSURLRequest *request = [NSURLRequest requestWithURL:urlToFile];
[webView loadRequest:request];
}
I ended up using the documentInteractionController for this to display the PDF in Quick Look. There is a great tutorial for this in the 2010 WWDC vids.
No idea why it wasn't working well in webView, but it's smooth as silk in Quick Look.
The first thing I would look at is the PDF its self. Often people try loading huge PDF files and expect them to perform wonderfully. Can you post the PDF for us to see? How large is the file? Remember that the PDF file size is the compressed size, to display images in the PDF they will be uncompressed when stored in RAM. Its not uncommon for a 500KB image on disk to use 20 MB in memory (This applies for all raster graphics, not just PDFs). This is usually the case when PDF performance is poor from what I've seen around here.
I know you said it works great in Safari, however we don't know what all Apple does in Safari's internals vs a UIWebView. Also Safari is usually running in the background, so it is using memory even when your app is running. This reduces mem that you app can use, but when you are running safari as the foremost app, 3rd party apps aren't using much memory, so safari could potentially cache more of the PDF at a time.