La aplicación de iOS se bloquea: sospecho que tiene que ver con UIWebView usando WebSockets

Actualmente no estoy usando applicationWillResignActive / applicationWillEnterForeground ni nada similar, ya que no estoy seguro exactamente cómo manejar este problema en el que me estoy topando.

Mi aplicación sigue fallando si la abro, presiono la pantalla de inicio, espero unos 5 minutos e bash volver a entrar en la aplicación.

La aplicación es principalmente una UIWebView que carga un websocket de node.js, así que creo que es el culpable.

¿Cómo puedo evitar que UIWebView haga cualquier cosa / todo cuando el usuario abandona la aplicación (applicationWillResignActive es lo que supongo que debe usar). He jugado con media docena de ideas y no puedo evitar que la aplicación deje de estrellarse.

Mi idea actual:

- (void)applicationWillResignActive:(UIApplication *)application { [[NSNotificationCenter defaulCenter] postNotificationName:@"EnterBackground" object:Nil userInfo: Nil]; } 

… y luego desde allí edito mi file ViewController.m para hacer algo al UIWebView en esa página. El problema es, ¿qué impedirá que UIWebView haga algo mientras está en segundo plano? He intentado detenerlo y, por alguna razón, no tuve éxito, o aún se queuepsaría.

No pude reproducir el problema exacto ( WebThread: EXC_BAD_ACCESS (code=1, address=0x5) -toma de tu otra pregunta ), pero noté que los posts de WebSocket estaban siendo almacenados en el búfer, por lo que tal vez si abandonas la aplicación en el background el time suficiente, golpeará un problema de presión de la memory que puede ser la causa de este locking.

Sin embargo, en el process de investigación de esta pregunta, logré hacer que la aplicación falla de manera confiable con un EXC_BAD_ACCESS origina en WebThread así que publicaré los detalles aquí con la esperanza de que sea útil para usted u otra persona.

A los efectos de esta pregunta, mi server WebSocket simplemente transmite el time cada segundo a cualquier cliente conectado.

Como mencioné, noté que UIWebView estaba almacenando en búfer los posts de WebSocket cuando la aplicación estaba en segundo plano. Para evitar esto, quería cerrar la connection de WebSocket cuando la aplicación se movió al background.

En mi opinión, el controller que aloja el UIWebView, registré un selector para UIApplicationWillResignActiveNotification y en ese selector, llamé a una function de JavaScript en mi página web que llamó close del object WebSocket.

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();"]; } 

Página web:

 function closeWebSocket() { socket.close(); // socket is an instance of WebSocket socket = undefined; } 

Quería que el WebSocket se volviera a conectar cuando la aplicación volviera a moverse al primer plano, por lo que UIApplicationDidBecomeActiveNotification otro selector, esta vez para la UIApplicationDidBecomeActiveNotification y en ese selector se llamó a otra function que inicializaría la connection WebSocket.

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();"]; } 

Página web:

 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"); }; } 

Al ejecutar la aplicación, se estableció la connection de WebSocket, se recibieron posts y la aplicación se movió al background. Después de unos segundos, volví a poner la aplicación en primer plano (tocando el icono de la aplicación) y la aplicación se bloqueó con una exception similar a WebThread: EXC_BAD_ACCESS (code=1, address=0x5 . La causa de esto fue la evaluación de la llamada JavaScript a openWebSocket() cuando la aplicación volvió al primer plano. El retraso de la ejecución de openWebSocket() por unos pocos milisegundos solucionó el problema. El método appDidBecomeActive terminó así:

 - (void)appDidBecomeActive:(NSNotification *)notification { [self.webView stringByEvaluatingJavaScriptFromString:@"setTimeout(openWebSocket, 5);"]; } 

Al ejecutar la aplicación de nuevo, se estableció la connection de WebSocket, los posts recibidos y la aplicación en segundo plano. Cuando volví a poner la aplicación en primer plano unos segundos después, la aplicación no se bloqueó y los posts comenzaron a conectarse nuevamente a través de WebSocket.