iOS: Guard against this and self being deleted when using dispatch_async

When the QIOSApplicationState object owned by the platform integration
was deleted we would deallocate QIOSApplicationStateListener, but would
then get a callback on the main queue later on where we would reference
the now invalid 'this' variable.

By moving the dispatch_async call to QIOSApplicationStateListener and
using 'self' we ensure that the listener is retained for as long as the
block is valid. This opens us up for receiving application state callbacks
after QCoreApplication has been deleted, so we need to guard against
that.

Change-Id: I2ac14d28d72fd79764e12b6657234b54d846cb79
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
Tor Arne Vestbø 2013-09-03 14:49:09 +02:00 committed by The Qt Project
parent ba7da9b733
commit fc2b36ca1d
2 changed files with 18 additions and 8 deletions

View File

@ -42,6 +42,8 @@
#ifndef QIOSAPPLICATIONSTATE_H
#define QIOSAPPLICATIONSTATE_H
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
@class QIOSApplicationStateListener;

View File

@ -39,10 +39,12 @@
**
****************************************************************************/
#import <UIKit/UIKit.h>
#include "qiosapplicationstate.h"
#include <qpa/qwindowsysteminterface.h>
#include "qiosapplicationstate.h"
#include <QtCore/qcoreapplication.h>
#import <UIKit/UIKit.h>
@interface QIOSApplicationStateListener : NSObject
@end
@ -71,6 +73,12 @@
selector:@selector(applicationDidEnterBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
// Update the current state now, since we have missed all the updates
// posted from AppKit so far. But let QPA finish initialization first.
dispatch_async(dispatch_get_main_queue(), ^{
[self handleApplicationStateChanged:[UIApplication sharedApplication].applicationState];
});
}
return self;
}
@ -112,6 +120,12 @@
- (void) handleApplicationStateChanged:(UIApplicationState) uiApplicationState
{
// We may receive application state changes after QCoreApplication has
// gone down, as the block we schedule on the main queue keeps the
// listener alive. In that case we just ignore the notification.
if (!qApp)
return;
Qt::ApplicationState state;
switch (uiApplicationState) {
case UIApplicationStateActive:
@ -145,12 +159,6 @@ QT_BEGIN_NAMESPACE
QIOSApplicationState::QIOSApplicationState()
: m_listener([[QIOSApplicationStateListener alloc] init])
{
// Update the current state now, since we have missed all the updates
// posted from AppKit so far. But let QPA finish initialization first:
dispatch_async(dispatch_get_main_queue(), ^{
UIApplicationState state = [UIApplication sharedApplication].applicationState;
[m_listener handleApplicationStateChanged:state];
});
}
QIOSApplicationState::~QIOSApplicationState()