If I have a UIWebView with mediaPlaybackRequiresUserAction = YES, then later in my app create a new UIWebView and set mediaPlaybackRequiresUserAction = NO on it, it also changes the value of that property on the first instance.
e.g. I have a UIWebView and then present a second UIWebView modally (for an ad), changing mediaPlaybackRequiresUserAction on the modal webView affects the presenting UIWebView.
Any ideas why this is? Are UIWebViews all backed by a single instance?
Link to sample project here.
not sure your app purpose, just try this way:
- (IBAction)unwind:(UIStoryboardSegue *)unwindSegue
{
[self TS_updateLabel];
[[self webView] setMediaPlaybackRequiresUserAction:YES];
[self TS_reloadWebView];
}
....
in method TS_reloadWebView
if (self.webView.isLoading) {
[self.webView stopLoading];
}
[self.webView loadHTMLString:htmlString baseURL:baseURL];
I guess it also is UIWebView bug .... but now this way maybe can solve your problem.
Related
I have tried all these (one, two, three, four) solutions, but after I come back from web view screen to previous viewController, it freezes for around 2 seconds(sometimes more). There is nothing in viewWillAppear which will cause the freezing.
Here is viewWillDisappear of web view controller :
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[detailWebView stopLoading];
detailWebView.delegate = nil;
NSLog(#"viewWillDisappear called !!!");
}
First viewController :
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController.navigationBar setBarTintColor:[UIColor colorWithRed:41.0/255.0 green:151.0/255.0 blue:132.0/255.0 alpha:1.0]];
UIImage *imagePlus = [[UIImage imageNamed:#"create.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
buttonCreate = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonCreate setImage:imagePlus forState:UIControlStateNormal];
[buttonCreate addTarget:self action:#selector(createActivity:) forControlEvents:UIControlEventTouchUpInside];
buttonCreate.frame = CGRectMake(self.view.frame.size.width - 40, 10, 16, 16);
[self.navigationController.navigationBar addSubview:buttonCreate];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"back", nil) style:UIBarButtonItemStylePlain target:nil action:nil];
[backButton setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal];
self.navigationItem.backBarButtonItem = backButton;
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
}
Update : I just confirmed that if I let the webView load completely and then go to previous viewController, there is no freeze observed.
I do the following, which is similar to what #Mrunal suggests but loads a valid page. I originally added this to deal with a situation where a loaded page had timers which continued to run forever after popping back from a UIWebView. For me this works well.
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Load a blank page as found things hang around.
[self.theWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
}
NB I do not call stopLoading as that stops the load request. This could be what is wrong with Mrunal's solution?
Try this in viewWillDisappear:
-(void)viewWillDisappear:(BOOL)animated {
[detailWebView setDelegate:nil];
[detailWebView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString:#""]]];
[detailWebView stopLoading];
[super viewWillDisappear:animated];
}
Are you using NSURLProtocol to intercept the web requests from your UIWebView? The below answer is written on that assumption.
Loading of the web page involves sending out requests for multiple resources ( images, videos, html, javascript). Each of those resources have an URL that will be intercepted by the NSURLProtocol
Now if you close the webView before all the resources are loaded, NSURLProtocol takes sometimes to cancel all the open requests for resources it is intercepting and in this process freezing your app.
You will unregister from NSURLProtocol before you exit out of webView. So
override func viewWillDisappear{
NSURLProtocol.unregisterClass(/*your custom url protocol class name here*/)
}
should fix the freezing issue
PS: Sometimes you might have NSURLProtocol defined for the entire app, in which case I think it is better to separate out the NSURLProtocol for UIwebView from the rest of app. I don't know much about your project for me to comment if this is a feasible option for you
I think the webview might still process in the background. And I made the experience that it is quite annoying to release a UIWebView completely. You might want to have a look in the Profiler: up and close the webview's ViewController several times, the buffer should steadily increase.
This is why I came up to merge several solution approaches from stack overflow to finally and completely remove all storage from a webview and also stop it from running.
It is crucial, that the webview is set to be nil, to really deallocate it's memory, in former days we had the release method, which is now "obsolete" if you make use of the ARC properly.
- (void)releaseWebView:(UIWebView *)webView
{
/*
There are several theories and rumors about UIWebView memory leaks, and how
to properly handle cleaning a UIWebView instance up before deallocation. This
method implements several of those recommendations.
#1: Various developers believe UIWebView may not properly throw away child
objects & views without forcing the UIWebView to load empty content before
dealloc.
Source: http://stackoverflow.com/questions/648396/does-uiwebview-leak-memory
*/
[webView loadHTMLString:#"" baseURL:nil];
/*
#2: Others claim that UIWebView's will leak if they are loading content
during dealloc.
Source: http://stackoverflow.com/questions/6124020/uiwebview-leaking
*/
[webView stopLoading];
/*
#3: Apple recommends setting the delegate to nil before deallocation:
"Important: Before releasing an instance of UIWebView for which you have set
a delegate, you must first set the UIWebView delegate property to nil before
disposing of the UIWebView instance. This can be done, for example, in the
dealloc method where you dispose of the UIWebView."
Source: UIWebViewDelegate class reference
*/
[webView setDelegate:nil];
/*
#4: If you're creating multiple child views for any given view, and you're
trying to deallocate an old child, that child is pointed to by the parent
view, and won't actually deallocate until that parent view dissapears. This
call below ensures that you are not creating many child views that will hang
around until the parent view is deallocated.
*/
[webView removeFromSuperview];
webView = nil;
}
Please give it a try and call this method in viewWillDisappear:
I m just trying to fix all the contents of html according to the device screen.
I have to put html data at proper place for iPhone & iPad in webview.
Please help me!!!
I am going to assume that this question is a very basic one.
Suppose that you have placed a UIWebView in a view in your storyboard, and you have set layout constraints so that the UIWebView fills the view.
Then
Add an IBOutlet to your view controller, and connect it to the web view.
In the view controllers viewDidLoad: method, tell the web view what to display. Here is an example:
-(void)viewDidLoad {
[super viewDidLoad];
NSURL* url = [NSURL URLWithString:#"http://www.apple.com"];
NSURLRequest* r = [NSURLRequest requestWithURL:url];
[_webView loadRequest:r];
}
This loadRequest: call is asynchronous, meaning that the page may not show up immediately.
If this is not answering your question, please add more information.
Before I present my issue, I want to mention that I tried looking for solutions here and here.
I am creating a hybrid application which uses native UIWebView for rendering the responsive designed web application. Following is the issue description :
1. I have a UITabBarController.
2. Each of the tab has a UIWebView.
3. I have to preload all tabs.
4. I am showing a UIActivityIndicator till the content loads on the first tab.
5. White screen appears for about 8-10 seconds and then the content starts to appear.
I will be happy to see this time become 2-4 seconds.
Following is my implementation :
[self performSelectorOnMainThread:#selector(loadAllTabs) withObject:nil waitUntilDone:YES];
-(void) loadAllTabs
{
for(UIViewController * viewController in self.viewControllers){
if(![[NSUserDefaults standardUserDefaults]boolForKey:#"isSessionExpired"])
{
if((int)[self.viewControllers indexOfObject:viewController] != 4)
{
viewController.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:viewController];
[viewController view];
}
}
}
}
In WebView controller's viewDidLoad I have :
[_tgWebView loadRequest:[NSURLRequest requestWithURL:homeURL]];
I was looking forward to suppressesIncrementalRendering, but since I am preloading all tabs, this does not work.
Since my app supports iOS 7+, thus WKWebView can't be applied here.
I also thought of increasing the launch image duration but learned that is won't be a good practice.
Can this be implemented using GCD?
Please bring out the pitfalls in my implementations so that my application makes better performance.
First, have UIWebView on each tab hidden until it has finished loading, then show it. Underneath the UIWebView you can have some placeholder image to describe it loading. Then using the webViewDidFinishLoad delegate method show the web view when it has finished loading. This approach will be non blocking.
- (void)webViewDidFinishLoad:(UIWebView *)webview
{
if (webview.isLoading)
return;
else
webView.hidden = false;
}
Second, preload the first tab then load the subsequent tabs while displaying the first. You can do that by placing the following code in the first tabs viewDidLoad method:
// Preload the subsquent tabs
for (UIViewController *aVC in self.tabBarController.viewControllers)
if ([aVC respondsToSelector:#selector(view)] && aVC != self)
aVC.view;
This way, the additional tabs web views are loaded in the background in a non blocking manner. You could combine it with hiding the web views while loading in case the user navigates to the additional tabs before their pages load.
I tested this with three tabs and it worked nicely.
So the first view controller could look something like this:
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Load the website
[self loadWebView];
// Preload the subsquent tabs
for (UIViewController *aVC in self.tabBarController.viewControllers)
if ([aVC respondsToSelector:#selector(view)] && aVC != self)
aVC.view;
}
-(void)loadWebView
{
// Create Request
NSURL *url = [NSURL URLWithString:#"http://anandTech.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Load the page
[webView loadRequest:request];
}
- (void)webViewDidFinishLoad:(UIWebView *)webview
{
if (webview.isLoading)
return;
else
webView.hidden = false;
}
EDIT:
Removed GDC as it was crashing when the views had WebViews
This post made my day. I am now using NSNotificationCenter for this.
It's hard to identify the where the problem is directly.
First, I suggest that you check your network connection by loading the page on a desktop machine on the same Wifi to see if it is your server that is too slow.
Also you can load your pages one by one instead of load all pages concurrently, since multiple HTTP request are not processed in a FIFO sequence, they may be processed out of order, and your page may need all resource to be loaded before displaying.
Do you control the web page your self? You can use safari inspector to inspect your web page to see where is the time spent, is it resource loading, javascript processing or rendering.
I am developing an app in Xcode but am having trouble with one part.
Basicly on the main app page, there is a small section that contains a web view. Everytime I change to another view controller and back, i see it flicker and reload. Is there a way to prevent it from reloading every time i open the view? instead just reloading every time I open the app.
This is the code:
NSURL *webUrl = [NSURL URLWithString:#"myurl.com"];
NSURLRequest *webrequestUrl = [NSURLRequest requestWithURL:webUrl];
[webView loadRequest:webrequestUrl];
webView.scrollView.scrollEnabled = NO;
webView.scrollView.bounces = NO;
Your webview is reloading every time you go to that screen is probably because you added it to either viewDidAppear: or viewWillAppear.
Add your block of code to the viewDidLoad method so it only gets executed when the view is loaded (aka when it's shown for the first time).
- (void)viewDidLoad:(BOOL)animated {
NSURL *webUrl = [NSURL URLWithString:#"myurl.com"];
NSURLRequest *webrequestUrl = [NSURLRequest requestWithURL:webUrl];
[webView loadRequest:webrequestUrl];
webView.scrollView.scrollEnabled = NO;
webView.scrollView.bounces = NO;
}
Edit: Oh by going to another view and back you meant going back on the navigation stack (or switching the navigation stack). In that case, you can keep a strong reference to your view controller with the webview and reuse it. Though I wouldn't suggest it doing it this was, unless that screen is the most important screen of your application.
Hope you are having your logic in other than the method
- (void)viewDidLoad
move your code to - viewDidLoad
even if your are having trouble then pass the preloaded UIWebView when ever you are navigating.
I have a method that loads the content in my WebView:
-(void)loadContent:(NSURLRequest *)requestObj{
//Load the request in the UIWebView.
[webView loadRequest:requestObj];
webView.delegate = self;
NSLog(#"LOAD WEBSITE!!!");
}
when I first call it like this:
[self loadContent:requestObj];
it works fine! But when I call it again for a new URL, it does not work.
I have readed that it will help to call the following before loading the new URL:
[webView stringByEvaluatingJavaScriptFromString:#"document.open();document.close()"];
But it doesn't change the result. Does anyone know how to handle this? Please be patient with me, I'm new in the iOS-world.
Ok i find out, my WebView is Null, but why? I call it from the ViewController and it has to be there. Does someone know how to handle this?
UPDATE: It is not Null any more cause i do this:
if(!webView)
{
webView = [[UIWebView alloc]init];
}
But it does not change the content when i do this: [webView loadRequest:requestObj];
try reloading the view like self reload.nameOfTheView
Is your webview created in a nib? If so, it may not be connected.
http://sweng.epfl.ch/tutorials/getting-started-with-ios-developement-xcode-and-objective-c
you can go through the above link and find a step by step procedure
http://www.raywenderlich.com/2712/using-properties-in-objective-c-tutorial
you can download a sample code from the above link.