I am not currently using applicationWillResignActive / applicationWillEnterForeground or anything similar, as I'm not sure exactly how to handle this issue I'm running into.
My app keeps crashing if I open it up, press home screen, wait about 5 minutes, and try to go back into the app again.
The app is mainly a UIWebView that loads a node.js powered websocket, so I think that is the culprit.
How can I stop the UIWebView from doing anything/everything when the user leaves the app (applicationWillResignActive is what I'm guessing needs to be used). I have played with a half dozen ideas and I cannot for the life of me get the app to stop crashing.
My Current Idea:
- (void)applicationWillResignActive:(UIApplication *)application
{
[[NSNotificationCenter defaulCenter] postNotificationName:@"EnterBackground" object:Nil userInfo: Nil];
}
...and then from there I edit my ViewController.m file to do something to the UIWebView on that page. The problem is, what will stop the UIWebView from doing anything while in the background? I have tried stoploading, and for some reason had no success, or it would still crash.
I couldn't reproduce the exact issue (WebThread: EXC_BAD_ACCESS (code=1, address=0x5)
—taken from your other question), but I did notice that the WebSocket messages were being buffered, so it maybe that if you leave the app in the background long enough, you will hit a memory pressure issue that may be the cause of this crash.
However, in the process of researching this question I did manage to make the app reliably crash with a EXC_BAD_ACCESS
originating from the WebThread
so I'll post the details here in the hope it may be of use to you or someone else.
For the purposes of this question, my WebSocket server simply broadcast the time every second to any connected clients.
As I mentioned, I had noticed that the UIWebView was buffering the WebSocket messages when the app was backgrounded. To prevent this, I wanted to close the WebSocket connection when the app was moved into the background.
In my view controller hosting the UIWebView, I registered a selector for UIApplicationWillResignActiveNotification
and in that selector, I called a JavaScript function in my web page that called close
on the WebSocket object.
ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
}
- (void)appWillResignActive:(NSNotification *)notification
{
[self.webView stringByEvaluatingJavaScriptFromString:@"closeWebSocket();"];
}
Web Page:
function closeWebSocket() {
socket.close(); // socket is an instance of WebSocket
socket = undefined;
}
I wanted the WebSocket to reconnect when the app was moved back into the foreground, so I registered another selector, this time for the UIApplicationDidBecomeActiveNotification
and in that selector called another function that would initialise the WebSocket connection.
ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}
- (void)appWillResignActive:(NSNotification *)notification
{
[self.webView stringByEvaluatingJavaScriptFromString:@"closeWebSocket();"];
}
- (void)appDidBecomeActive:(NSNotification *)notification
{
[self.webView stringByEvaluatingJavaScriptFromString:@"openWebSocket();"];
}
Web Page:
function openWebSocket() {
socket = new WebSocket("ws://" + document.location.host + "/ping");
socket.onopen = function () { console.log("Opened"); };
socket.onmessage = function (message) {
var log = $('#log');
log.html(message.data + '<br>' + log.html());
console.log(message.data);
};
socket.onclose = function () { console.log("Closed"); };
}
Running the app, the WebSocket connection was established, messages were received, and the app moved into the background. After a few seconds, I brought the app back to the foreground (by tapping on the app icon) and the app crashed with an exception similar to WebThread: EXC_BAD_ACCESS (code=1, address=0x5
. The cause of this was the evaluation of the JavaScript call to openWebSocket()
when the app was brought back to the foreground. Delaying the execution of openWebSocket()
by a few milliseconds fixed the issue. By appDidBecomeActive
method ended up looking like this:
- (void)appDidBecomeActive:(NSNotification *)notification
{
[self.webView stringByEvaluatingJavaScriptFromString:@"setTimeout(openWebSocket, 5);"];
}
Running the app again, the WebSocket connection was established, messages received, and the app backgrounded. When I brought the app back into the foreground after few seconds later, the app did not crash and the messages started coming through WebSocket connection again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With