iOS应用程序崩溃 - 我怀疑与使用WebSockets的UIWebView有关。

5

我目前没有使用applicationWillResignActive/applicationWillEnterForeground或类似的内容,因为我不确定如何处理我遇到的问题。

如果我打开应用程序,按home键,等待约5分钟,然后再次尝试进入应用程序,我的应用程序就会崩溃。

该应用程序主要是一个加载基于node.js的websocket的UIWebView,所以我认为那就是罪魁祸首。

如何在用户离开应用程序时停止UIWebView执行任何操作/所有操作(我猜测需要使用applicationWillResignActive)。我已经尝试了半打想法,但是我无论如何也无法阻止应用程序崩溃。

我目前的想法:

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

然后我会编辑ViewController.m文件,对该页面上的UIWebView进行操作。问题是,在后台时如何阻止UIWebView执行任何操作?我尝试了stoploading,但不知何故没有成功,或者仍然会导致崩溃。


1
你是否正在自定义NSUrlProtocol?并在你的webView控制器中执行类似registerClass的操作?请发布你的崩溃日志或webView代码。 - johnMa
你能找出应用程序崩溃的原因吗? - sunkehappy
2
显示崩溃的堆栈跟踪。 - Phillip Mills
1个回答

6

我无法复现确切的问题(WebThread: EXC_BAD_ACCESS (code=1, address=0x5)—摘自你的其他问题),但我注意到WebSocket消息正在缓冲,如果你把应用程序留在后台足够长的时间,可能会导致内存压力问题,这可能是此崩溃的原因。

然而,在研究这个问题的过程中,我确实成功地让应用程序崩溃,并出现了源自WebThreadEXC_BAD_ACCESS,所以我会在这里发布详细信息,希望能对您或其他人有所帮助。

为了解决这个问题,我的WebSocket服务器简单地广播当前时间给任何连接的客户端。

正如我之前提到的,当应用程序进入后台时,我注意到UIWebView正在缓冲WebSocket消息。为了防止这种情况发生,我想要在应用程序进入后台时关闭WebSocket连接。

在托管UIWebView的视图控制器中,我为UIApplicationWillResignActiveNotification注册了一个选择器,并在该选择器中调用了我的Web页面中的一个JavaScript函数,该函数在WebSocket对象上调用了close

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

网页:

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

我希望WebSocket在应用程序回到前台时重新连接,因此我注册了另一个选择器,这次是为UIApplicationDidBecomeActiveNotification注册的,并在该选择器中调用另一个函数来初始化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();"];
}

网页:

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

运行应用程序时,WebSocket连接已建立,消息已接收,并且应用程序进入后台。几秒钟后,我通过点击应用程序图标将其带回前台,但是应用程序崩溃并出现类似于 WebThread: EXC_BAD_ACCESS (code=1, address=0x5 的异常。原因是在将应用程序带回前台时评估了对 openWebSocket() 的JavaScript调用。将openWebSocket()的执行延迟几毫秒可以解决此问题。我的appDidBecomeActive方法最终看起来像这样:

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

再次运行应用程序,WebSocket连接建立,消息接收并将应用程序置于后台。几秒钟后,当我将应用程序重新带回前台时,应用程序没有崩溃,并且消���再次通过WebSocket连接传输。

@neilco 给出了很不错的答案。一个建议,你能否直接使用 Javascript 中的暂停/恢复事件?它们应该可以很好地转化为 appWillResignActive/appDidBecomeActive 的事件。 - Marko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接