UIWebView load HTML page which consists jpeg image representation - ios

I've setup simple test project with UIWebView and button action:
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.netvlies.nl/wp-content/uploads/2012/07/wolk_600px_jpg_quality_50_progressive_11kb.jpg"]]];
Why each load request there is new ImageIO_jpeg_data and allocated memory size for that much bigger then actual image size?
I know there are lot of controversial posts about UIWebView leaks, how to clean it, so on.

Related

How to keep UIWebView from caching images?

I am using UIWebView to display an HTML page inside an IOS app. The HTML page contains a png file that I create on the local disk and write to. Everything works fine the first time I display the page, but when I try to create a new image and redisplay the page, the original image is displayed.
The issue appears to be that I am using the same file name for the PNG file. Even though I write to the PNG file with a new image, the UIWebView is caching the image from the original load, and displays the original image, not the new one. I have verified that the new image is being written to correctly by loading it into Safari.
So how can I clear the UIWebView's cache of this image? I realize that another option would be to give the png file a different file name each time I create it, but then I'd either accumulate png files or I'd have to add code to clear out the png files when done - which I'd rather not do.
Have a look at this answer:
NSString *testURL = [NSString stringWithFormat:#"%#?t=%#", url, randQuery];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:testURL] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10.0]];
You can try:
NSString *theURL = [NSString stringWithFormat:#"%#?t=%#", url, [[NSProcessInfo processInfo] globallyUniqueString]];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:theURL] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:8.0]];

UIWebView serialization after content has been rendered

I have a very large HTML Document that I need to show in my app. It utilizes CSS Columns, and scrolls horizontally. What I try to do is archive the UIWebView that renders the document in its current state, so that I can unarchive it from CoreData and don't have to let the user wait for a few seconds until it's rendered. So inside my UIWebViewDelegate, I serialize using the following method when webViewDidFinishLoad is called (the content is loaded from string, not from external sources):
[NSKeyedArchiver archivedDataWithRootObject:self.webView];
I checked if webViewDidFinishLoad is called multiple times, but it isn't. This and the core data saving actually works, i.e. it does save and load properly the next time the app is launched. However, while it saves the UIWebView itself, it seems like the content isn't loaded into it, which makes the whole procedure kinda useless for my purpose. Is my understanding of saving an object this way wrong, or is it simply a question of implementation?
Many thanks!
I dont think you should be archiving the UIWebview. Instead you can save the html document fil with custom CSS elements in the documents directory of the app and render it using the filepath using the following code.
self.webview.scalesPageToFit= YES;
[self.webview loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];

massive memory leak in ios UIWebView

looking for mem leaks elsewhere in our system, I created a 20 MB web page with a meta refresh tag. the idea was to move a lot data through our datapath code to confirm mem stability.
<html>
<meta http-equiv="refresh" content="1">
<body>
<div style="border: 1px solid red">
Content loading
</div><!-- 20mb worth of comments -->
</body>
</html>
what I found was the uiwebview displaying that meta refresh page leaks memory very, very fast. the app memory hits 300mb in about 2 minutes and gets shot on a low mem warning, even when our code is not in play.
I have stopped the refresh loading and tried to dealloc the webview.
I have tried loadurl:"about:blank", loadhtml:"", javascript document close.
I also tried writing a recursive removeFromSuperview and removeFromParentViewController, reading that the private scrollview in the webview is a memory problem, but that memory is never freed. I can't seem to find a reliable way to close, dealloc a webview when we are done with it.
We have lived with a slow rate of webview leaking for quite a while and really want to find a way of assuring a webview can be fully cleaned up when we are done with it. We recently converted the app to ARC which did not change the memory rate.
I am considering trying a recursive loop through all the objects in the webview and see if they can be freed. instruments shows 20 mb of cfdatas, alive, for each refresh of the 20MB page, but does not show them as leaks. if i only deliver the response header and done to the urlprotocol client we run stably so was ale to confirm the memleaks in the rest of the data path, but this is such a dramatic test case result am hoping to find a webview mem leak solution once and for all.
Does any one have any better ideas or has anyone tried recursing through the objects in a uiwebview?
The way I got rid of my UIWebView's memory leakage is by setting its HTML to the empty string. One place to do this is when the view controller containing the web view disappears:
- (void) viewWillDisappear:(BOOL)animated {
if (self.isMovingFromParentViewController) {
[self.wv loadHTMLString: #"" baseURL: nil];
}
}
A shout to all developers: Implementing didReceiveMemoryWarning is an absolute must when using a UIWebView!
And it's specially important when the UIWebView can navigate anywhere or to a page you know that causes UIWebView to have huge leaks, such as m.youtube.com.
A great and usually seamless way to fix the leaks is just reloading the page. In that way you don't need to care about the page becoming empty, and usually the user will be able to continue its work from where he left off.
In your view controller, override didReceiveMemoryWarning like this:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
[myWebView reload];
}
With iOS 8 and onwards, you are really in luck. WKWebView does not leak and has a much smaller memory footprint than UIWebView. Having tested it with image laden web pages containing complex Javascript, it performed well.
Apple's WKWebView Class Reference
nshipster on WKWebView
It's not perfect though. Then again hopefully imperfections will be resolved in time. Check out Shingo Fukuyama's tips on GitHub:
WKWebViewTips
Weakify "self" in the blocks.
This was one of the important reasons that lead to holding up of WebView memory even when popped out the navigation stack.

webViewDidFinishLoad did finish loading but didn't finish showing content on screen

I'm using webViewDidFinishLoad a lot in my app and there's something about UIWebView that really bugs me, well, actually two things.
The first, when I load new content to a UIWebView I will see for half a second the last page that was loaded to the same UIWebView what will force me to "clean" the UIWebView using something like:
[_mainWebView stringByEvaluatingJavaScriptFromString:#"document.open();document.close();"];
before loading the new content.
The second issue I have and that's the main issue for this question is that if i'll load some new content to my UIWebView and do something like this:
[_mainWebView loadHTMLString:htmlString baseURL:nil];
...
- (void)webViewDidFinishLoad:(UIWebView *)webView {
_mainWebView.alpha = 1;
}
In some cases the UIWebView will show up white for half a second before showing up the content. I'm guessing that the content is already loaded into the UIWebView and that's why webViewDidFinishLoad:webView is firing but for small html pages showing to content takes loner than the actual load. Is there any workaround I can use to avoid the blank screen that is showing for a sec or so but still save that second?
I thought about animating the alpha from 0 to 1 but that solution feels kinda lame to me.
Try adding a javascript callback so you know when the web view contents have actually loaded: Javascript in UIWebView callback to C/Objective-C

How to calculate scrollWidth of HTML page for fixed height without using UIWebView

We can use the following to calculate the scrollWidth of an HTML page in a UIWebView with a fixed height.
[webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.scrollWidth"]
Is it possible to do this evaluation on local HTML pages without loading a request into a UIWebView?
Would like this to occur on a separate thread.
No(sort of). The html would need to be rendered in some capacity to be able to get any kind of measurements. The reason for this is inherent in the way html/css/javascript work together (javascript modifies html/css properties, css modifies html). If you had to get the width without using a UIWebView, you would be stuck with one of two options:
Render the page yourself, whether it's with your custom code (thousands of man hours, don't do this) or some open source library. I doubt this will be any faster than UIWebView, and will likely introduce unexpected bugs.
Measure the page in the background, and store that value somewhere. This would basically be a form of caching for the size. If the pages are static from when you ship, just do it manually, and hard code it. If they are dynamic, write a class to measure them on startup and store the value. The dynamic measurement would require UIWebView
EDIT:
Are you trying to do this because UIWebView is blocking you're main thread, causing jerkiness in your app? If so, have you considered trying something like this?:
UIWebView *webview = [[UIWebView alloc] initWithFrame:CGRectMake(0,0,320,460)];
webview.delegate = self;
[webview loadRequest: [NSURLRequest requestWithURL:[NSURL urlFromString:#"/path/to/file.html"]]];
... and then later on...
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
// run your code to get scroll width of page
}

Resources