I'm loading a local html template with some js code into webview. It works most of the time. But sometimes, the shouldStartLoadWithRequest delegate gets called once and won't get called at all later. By the way, I'm seeing this issue more consistently in iOS 9.1 and above.
Whenever this issue occurs, if I recreate the webview and load same content, then it works fine. So, I wanted to know why it doesn't work the first time (inconsistent) but works the second time.
I'm calling
[_webView setDelegate:nil];
//and
[_webView stopLoading]; in dealloc method.
Would be helpful if anyone can suggest something.
I think somewhere your webView just loses its delegate. So it may just reset it with other one somewhere in code or just seed with nil. Looking to your posted code I can predict such situation - two instances has references to this webView. One instance should delete and it's calling dealloc method - webView delegate sets to nil, but other instance still using this same webView, but now it has delegate nil. As delegate is nil than webView won't send any message to him. It's only my prediction, still you'd should check if your delegate is nil or not and than begin new problem research. Good luck.
Related
I am using WKWebView in an application and sometimes I get a blank screen because the process dealing with content crashes.
WKNavigationDelegate has a webViewWebContentProcessDidTerminate: method and I implemented it in my view controller.
I can see the memory growth of the webkit process in Instruments but whenever the screen goes blank the methods never gets called.
Other methods of the delegate are working correctly.
Any ideas on this?
well, webViewWebContentProcessDidTerminate delegate can be called if process terminates. However, it is not called once the screen goes blank. There is a delay.
I am currently testing on iOS 8, on an iPhone 6. I am calling these APIs from Swift.
I'm trying to figure out why I can't call startRecordingToOutputFileURL more than once on a single instance of AVCaptureMovieFileOutput.
I am calling stopRecording before I call startRecordingToOutputFileURL again.
I am deleting the temporary video file before calling startRecordingToOutputFileURL.
The first time that I call startRecordingToOutputFileURL, the didStartRecordingToOutputFileAtURL delegate callback is fired. When I call stopRecording, the didFinishRecordingToOutputFileAtURL callback is fired.
After this, I delete the temporary file.
Then, when I call startRecordingToOutputFileURL the next time, the delegate callback is not fired. And when I call stopRecording a second time, the "finished" callback is not fired either.
The Apple docs for
startRecordingToOutputFileURL say the following:
In iOS, this frame accurate file switching is not supported. You must call stopRecording before calling this method again to avoid any errors.
However, I am calling stopRecording before calling it again, and it is not working.
My current workaround is to remove the AVCaptureMovieFileOutput connection, initialize a new instance of AVCaptureMovieFileOutput, and then set up a new connection. This is terrible, because it takes a long time and freezes the video preview.
Please let me know if you know why this is happening, and if there is a fix.
UPDATE: I just noticed that if I toggle my AVCaptureSession sessionPreset to AVCaptureSessionPresetPhoto and then back to AVCaptureSessionPresetHigh, then I can start capturing video again.
UPDATE 2: Here's another way I can fix the problem:
captureSession.stopRunning()
captureSession.startRunning()
UPDATE 3: It turns out that this seems to be related to some code that captures the volume buttons - JPSVolumeButtonHandler. It doesn't happen when I comment out the code that starts JPSVolumeButtonHandler.
I'm just experiencing something weird and it seems to be a change in iOS 8.
Previously(iOS7) when testing appWillBecomeActive was called before viewDidAppear. Is it so that in iOS 8 it is the other way around? what would then be a good workaround in order to make my app work on both iOS versions? is there some variable to test if viewDidAppear was called so I could run my setup functions of the view again?
EDIT: it actually seems quite random in iOS8. sometimes viewDidAppear is called before appWillBecomeActive. Sometimes it's the other way around...
appWillBecomeActive is a delegate located in your Application Delegate itself.. there's no guarantee that it will be called before any other UIViewController delegates (viewWillAppear,DidLoad,Init)
if you want to make any logic before loading of any other pages come alive.. you may want to use application:didFinishLaunchingWithOptions: and you may want to load the launching view by yourself or create a new delegate to detect that you finished the logic that you'll put in your application:didFinishLaunchingWithOptions: .
In my app when i load UIWebView with any Website url the memory jumps from 30mb to around 140mb.
I am using ARC
and when dismissing the UIWebViewController[Viewcontroller which contains UIWebView], it doesnt releases the memory.
Can any body help me how to solve this memory issues as well as please also provide me pointers of memory bestpractices in ARC
For loading the webpage :-
NSURL *nsurl=[NSURL URLWithString:self.url];
NSURLRequest *nsrequest=[NSURLRequest requestWithURL:nsurl];
[webview loadRequest:nsrequest];
FOr Dismissing the Viewcontroller:-
[self dismissViewControllerAnimated:YES completion:^{
webview.delegate=nil;
webview=nil;
}];
Thanks in Advance :)
wow, today we also meet this problem. when we try to load a web page which contain lots pictures or a huge web page, it's easy to crash. we also find the memory used nearly 200M.
finally we find that we could remove the memory cache of web view
[[NSURLCache sharedURLCache] removeAllCachedResponses];
you can try it when you receive memory warning. or you can call it in the dealloc method.
if it still have some problems, try to limit the memory cache size by call
[[NSURLCache sharedURLCache] setMemoryCapacity:size]
good luck!
Don't listen to them,
Its not a problem, phones can handle all that memory usage, try using an MKMapView and watch your memory usage soar.
In your simulator, try putting through a low memory warning cmd+shift+m, and see what happens, you can't expect all web views to run at the same memory usage, also, you have give a chance for your phone to buffer it all out.
iPhones can handle all of that, so you shouldn't worry much about it.
But try this anyway:
The behaviour of UIWebViews changes if you uncheck "Detects Links" in the nib file, so try toggling that and see what happens.
Use Instruments Allocation tab to see the number of instances of your UIWebViewController live in memory. (Cmd + I in Xcode, let Instruments open, select Allocations, and type UIWebViewController in the search bar)
If there's more than what you expect it to be, lookout for a retain cycle.
Try to use weak references within blocks instead of self.
Make sure you aren't holding a strong reference to the UIWebViewController object at
more than one place.
Put a breakpoint/NSLog in the dealloc method your viewController to see if it is being called.
There is no sense to search for a problem until you are sure that problem exists.
There are two possibilities why memory usage is so high:
1.UIWebView is not deallocated.
2.It is some system caching or some specific iOS memory processing algorithm.
In second case you can do nothing. To check first case you can try to use instruments or just subclass UIWebView and add logging to dealloc method.
#implementation MyUIWebView
- (void)dealloc
{
NSLog(#"MyUIWebView deallocated!");
}
#end
Do not forget to change UIWebView to MyUIWebView in your code.
And only if you will be sure that UIWebView is not deallocated you should start to search for strong pointers, retain circles and so on.
add
if (webView.isLoading){
webView.stopLoading;
}
webView.delegate=nil;
before this line
[self dismissViewControllerAnimated:YES completion...]
nil ing your webView should be taken care of by ARC. Don't refer to the web view in the completion block.
I think you forgot to remove the UIWebView from the view hierarchy. This would cause an extra retain count and prevent the memory from being reclaimed when you nil'd out the property.
Just some things you should check:
A controller has a strong reference to its view, and this view retains all the subviews as long as you keep them inside the view hierarchy, so any additional properties should be weak, including your webView property.
When using ARC there's no need to "nil" everything. ARC will nil all its strong references at dealloc automatically.
No need to do anything with weak references neither. Moreover on iOS 5+ weak references become nil automatically if the referenced object gets deallocated somewhere else.
I think that most likely your whole view controller is getting retained somewhere, and thus its view and the webView.
Make sure the you only keep weak references to the controller and let it be retained by a container or presenting controller so it gets released automatically as long as it gets popped or dismissed.
I was having the same problem in my application. I would recommend that you should use WKWebView. WKWebView was introduced with iOS 8.
You can read more about it here
apple documentation
The memory issue is definitely solved. You will get all the functionality from webview and some more(i.e. progress). Hope this helps
If you want to reduce the memory usage of UIWerview immediately, you can try:
1.
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
or
2.
[webview loadHTMLString: #"" baseURL: nil];
or
3.
[webview loadData:nil MIMEType:nil textEncodingName:nil baseURL:nil];
It worked to me.
I've read that reusing UIWebViews is kind of a bad practice. Some code I inherited at work is pushing a variety of content to a UIWebView. Powerpoints, Word documents, and video. This all works just fine under normal circumstances. When we get to switching out the content in the UIWebView too fast, it dumps.
My webView is set as a property. It is hooked up in IB just fine. Normal selection from our tableView loads local content just fine. It takes rapid fire selection of either the same cell or combinations of multiple to get it to crash.
I can capture some error messages for it for the webViewDidFailWithError. But those will trigger even without a crash.
Here is the error localized string.
The operation couldn’t be completed. (NSURLErrorDomain error -999.)
When the app does finally crash, it blows up on this goofy WebCore error.
If anyone has any links or some code examples how to handle this I would appreciate it. Maybe an example how to best reuse my webView property without blowing things up.
I would load some of my code, but there is a lot going on not related to the webView itself. All content being pushed to the webView is done via [self.webView loadRequest:request]; with the request being an NSURLRequest filled with the path to the local content.
I will be very appreciative if anyone can help me out on this one. Fingers crossed for something simple.
I'm not certain this way is the "best" way to solve the issue, but it does seem to be working quite well. Short, sweet, and it works.
I disabled userInteraction with the tableView that updates the content in the webView. Since you have to mash on it so much, missing a tap here or there probably won't be missed. So for now, this is the fix.
#pragma mark -
#pragma mark UIWebViewDelegate methods
-(void)webViewDidStartLoad:(UIWebView *)webView {
[self.tableView setUserInteractionEnabled:NO];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
[self.tableView setUserInteractionEnabled:YES];
}
// I re-enable on load failures as they can block you out entirely on fail
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[self.tableView setUserInteractionEnabled:YES];
}
If it’s crashing only when you tap quickly, could you put a gesture recognizer over it to act as a poor man's rate limiter?
Are you using [webview stopLoading]; before loading another request? What you might need to do is cancel or stop the current loading before trying to load a different one. The other option being restrict the user input.
In your UIWebViewDelegate, you could implement webView:shouldStartLoadWithRequest:navigationType: to return NO if there is already a request loading.
I can't help but think you'd be better off not re-using the UIWebView. Ditch the nib, create it programmatically and set it to nil and re-create/re-assign/re-alloc it when the data source changes.
On a different note I would make sure to use NSOperationQueue for the data loading.