UIWebView memory leaks. What is the magic to release unused resources? - ios

Although there are many discussions about the subject, I have not still found an answer.
The problem is, that after the UIWebView loads a page, it will never release all the used memory resources.
I have created an empty project. Just added the UIWebView. The memory used before loading a request (http://methodhome.com/cleanhappy) was 4.5MB, and after loading has completed - 70 ~ 90 MB.
After releasing the UIWebView, the used memory was still 55MB.
So it looks like there are about 50MB of leaked memory.
I have tried next methods:
[_webView stringByEvaluatingJavaScriptFromString:#"var body=document.getElementsByTagName('body')[0];body.style.backgroundColor=(body.style.backgroundColor=='')?'white':'';"];
[_webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML='';"];
[_webView stringByEvaluatingJavaScriptFromString:#"document.open();document.close();"];
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
[_webView loadHTMLString:#"" baseURL:nil];
[_webView stopLoading];
_webView.delegate = nil;
[_webView removeFromSuperview];
_webView = nil;
[[NSURLCache sharedURLCache] removeAllCachedResponses];
I have also tried setting:
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:#"WebKitCacheModelPreferenceKey"];
and have played with cache settings of memory and disk.
Nothing helped.
How can it be possible? How are the popular browsers are working like Safari and Chrome with such a leaks. What is the trick to release those resources?

How can it be possible?
UIWebView is an old API, based on WebKitLegacy. It's not deprecated for 1 single reason - Apple had no replacement (until iOS 9).
How are the popular browsers are working like Safari and Chrome with
such a leaks.
Safari is a browser, created by Apple itself. It can use any hacks and private APIs, restricted in AppStore. Actually, for now Safari behavior is very close to WKWebView's one. But it never was similar to UIWebView.
Only recently Google Chrome was able to migrate to WKWebView. See https://bugs.chromium.org/p/chromium/issues/detail?id=423444 for details. Before that, Google Chrome was facing the same problem.
What is the trick to release those resources?
I've tried a lot of tricks, but none of them worked for me. Unfortunately, the only solution is migration to WKWebView, introduced in iOS 8. Moreover, WKWebView had a lot of bugs under iOS 8, so in most cases it's usable only starting from iOS 9.

Related

How to open Safari from ios app with specified cookies

I want to open Safari from my iOS application with specified cookies. But i found that NSHTTPCookieStorage is not shared between apps in iOS. So i don't know how to do that. Please help.
I suggest to go with SFSafariViewController which will launch the web page inside your app and whatever the cookies you have those will be retained by SFSafariViewController without extra work.

removeCachedResponseForRequest not work in iOS 9.3.1

Does removeCachedResponseForRequest work. I am trying to clear cache of uiwebview.
Any alternative of removeCachedResponseForRequest except removeAllCachedResponses that can be used to achieve clearing cache of a webview.

Enable Application cache in WKWebView

I am aware that offline application cache is not supported in iOS WKWebView.
This is enabled in Safari, so I searched webkit project for the responsible code & found this
WKPreferences
- (void)_setOfflineApplicationCacheIsEnabled:(BOOL)offlineApplicationCacheIsEnabled;
Anyone familiar with this method? is it possible to enable app cache in iOS by accessing this private methods? (I am not going to ship the app to Appstore)
Update 2022
According to one of the comments below, this hack doesn't work anymore.
Yes, we can enable App cache by accessing private API
Create a category for WKPreferences and add to following method signature.
#interface WKPreferences (MyPreferences)
- (void)_setOfflineApplicationCacheIsEnabled:(BOOL)offlineApplicationCacheIsEnabled;
#end
(I tried performSelector:withObject: but it didn't work. No idea why)
After initializing the WKWebView, enable the appcache by calling the above method in the following object
[_wkWebView.configuration.preferences _setOfflineApplicationCacheIsEnabled:YES];
It will create the ApplicationCache.db file in the Cache directory and allow the web app to work offline.
Warning :
2.5. Apps that use non-public APIs will be rejected
According to this tweet from at Apple, as of iOS 10, App Cache is now supported in WKWebView:
https://twitter.com/andersca/status/743259582252879872
...as does this WebKit bug report:
https://bugs.webkit.org/show_bug.cgi?id=152490
I've tested this in WKWebView using this site:
http://webdbg.com/test/appcache/
and can confirm it works as expected both in the iOS Simulator and on devices running iOS 10.

UIWebView issue with iOS 6

I have a running application in appstore which contains UIWebView. It worked perfectly fine till iOS 6.0. In OS 6 some hyperlinks are not working but the same thing is working fine when I use the safari browser in iOS on the iPad.
Do I need to add some extra delegate methods to make it working?
Currently I m Using following code:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kAuthenticationURL]];
[request setValue:[NSMutableURLRequest userAgentRequests] forHTTPHeaderField:#"User-Agent"];
[request setHTTPMethod:#"POST"];
[request setHTTPShouldHandleCookies:YES];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSData *postData = [[NSString stringWithFormat:#"username=%#&code=%#", username, password]
dataUsingEncoding:NSASCIIStringEncoding];
[request setHTTPBody:postData];
delegate i have used:
1)
- (void)webViewDidStartLoad:(UIWebView *)webView
2)
- (void)webViewDidFinishLoad:(UIWebView *)webView
inside this method I have used the following for loading data:
[self.webView stringByEvaluatingJavaScriptFromString:#"window.location.reload = function(){};"];
3)
- (BOOL)webView:(UIWebView *)webViewshouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType`
Do i need to implement some thing extra for make it working in iOS 6?
Any help is appriciated...
Maybe you're having the same problem as described here: stringByEvaluatingJavaScriptFromString is not working in iOS 6 or here iOS 6 - UIWebView loadHTMLString not working properly
It seems iOS 6 loads and renders the page differently and could be stricter then 5
You could try to suppres iOS6's incremental rendering as stated here
suppressesIncrementalRendering
A Boolean value indicating whether the web view suppresses content rendering
until it is fully loaded into memory.
#property(nonatomic) BOOL suppressesIncrementalRendering
You could also try to debug using your mac as described here:
Additional tip: to debug javascript errors on iOS6, a new feature
makes it very simple:
Go to the "Settings" application in your iPhone, enter the "Safari" settings and tap on "Advanced" at the bottom, then enable the "WebKit
Inspector" from there
Display your page to be debugged on the screen (i.e. launch your app and go to your screen that contains the WebView to make it visible)
Plug your iPhone to your Mac via your USB cable
Open Safari.app on your Mac, go to the "Development" menu (1), select the menu item with the name of your iPhone and select your
application in the submenu.
You will then be able to debug your web page presented in your iPhone
using the powerful Web Inspector from your Mac, and can look into the
javascript console, the DOM tree, etc.
(1) If you don't have the "Development" menu in Safari on your Mac, you can enable it in the "Advanced" preferences tab of the Safari
application.
More on remote debugging can be found here (scroll all the way down to 'Remote Debugging') or here (WWDC video session: "Debugging UIWebViews and Websites on iOS")

failed to return after waiting 10 seconds - UIWebView loadHTMLString

when I load a UIWebView with the following code:
NSString *helpText = [NSString stringWithFormat:#"Lorem Ipsum"];
[self.helpWebView loadHTMLString:[NSString stringWithFormat:#"<html><head></head><body stlye=\"background-color: transparent;\"><div align='justify' style=\"color: #000000; font-family: Helvetica; font-size: %fem;\">%#</div></body></html>", fontSize, helpText] baseURL:[NSURL URLWithString:#""]];
I get this error, but only the first time when a WebView is loaded in my app:
void SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
And the text will load, but only after 10 seconds. But the UI is blocked for 10 Seconds. When I navigate through the app, other ("later") UIWebViews will load immediately and it is not related to this specific UIWebView, i.e. if I got to UIWebView A and then to UIWebView B, A will load after 10 seconds of UI blocking and B will load instantly. IF it starts with B and then goes to A, B will load after 10 seconds and A will load instantly. So, only the first UIWebView which is loaded creates a problem.
And I really only load the html above. Some douzen of characters, no JScript, no big tables, no funny html stuff. It will even block the UI and report the error message if I load a blank HTML-String.
I have not set any delegate stuff or something like this. I created the UIWebView in Interface Builder, connected it to the header via property and I am using loadHTMLString to get content into.
Important: I can currently only use the Simulator, so I cannot predict, whether this is only a Simulator issue. If you know it, please let me know. At the moment, I cannot test at a real device. The Simulator should not go into this error because of ressources however. I have a current MacBook Air and almost no extra programs installed ("clean installation" of Mac OS X Lion).
Another Point: The only reason why I use UIWebView is that I need full justification for the text. If this would work any other way, would help me too. At least from Android development, I know that there is no other way than a WebView.
I think the problem is solved with the update from today (iOS 6.1 SDK) and I also think it is related to the simulator. I think it is about interfering outgoing requests from skpaymenttransaction and other UIWebView... I am not sure about anything, however...

Resources