01-16-2013 12:20 AM - edited 01-16-2013 12:32 AM
I received segmentation fault after 5 or 6 times of switching pages using the application setscene command.
Process:
1. LoadMain, which displays a listView (setScene)
2. User clicks on the list view item, which will call load secondary and show secondary page (setScene)
3. User clicks on the button on the secondary page, which will call loadMain again
Repeat the process from 1 to 3
The code to call is similar to below. Basically the user repeated call loadMain and loadSecondary. After 5 to 10 times of switching different pages, I received segmentation fault.
Just wondering what could I do wrong with the following methods?
Thanks!
Process 954052814 (TestApplication) terminated SIGSEGV code=1 fltno=11 ip=7845df00(/base/usr/lib/qt4/lib/libQtDeclarative
bool App::loadMainQMLScene() {
QmlDocument *qml = QmlDocument::create("asset:///Primary.qml").parent
if (qml->hasErrors()) {
qDebug() << "qml has errors";
return false;
}
qml->setContextProperty("app", this);
qDebug() << "before createRootObject";
Page *aPage = qml->createRootObject<Page>();
if (!aPage) {
return false;
}
mainGroupModel = aPage->findChild<GroupDataModel*>("mainGroupModel"
mainList = aPage->findChild<ListView*>("mainList");
loadMainList();
Application::instance()->setScene(aPage);
return true;
}
bool App::loadSecondaryQMLScene() {
QmlDocument *qml = QmlDocument::create("asset:///Secondary.qml").pare
if (qml->hasErrors()) {
qDebug() << "qml has errors";
return false;
}
qml->setContextProperty("app", this);
navigationPane = qml->createRootObject<NavigationPane>();
if (!navigationPane) {
return false;
}
secondaryGroupModel = aPage->findChild<GroupDataModel*>("secondaryGroupM
secondaryList = aPage->findChild<ListView*>("secondaryList");
loadSecondaryList();
Camera *camera = navigationPane->findChild<Camera*>("myCamera");
QObject::connect(camera, SIGNAL(shutterFired()), this, SLOT(onShutterFired()));
qDebug() << "before setScene";
Application::instance()->setScene(navigationPane)
return true;
}
01-16-2013 01:52 AM
QmlDocument *qml = QmlDocument::create("asset:///Primary.qml").parent (this);
Every call to QmlDocument::create() creates a new instance of QmlDocument which isn't destroyed until 'this' (application instance) is destroyed. So these instances are accumulating. Try destroying it explicitly at the end of function and in if-s:
delete qml;
I see nothing wrong in other code, the error might be in other functions.
Try adding more logging between function calls to isolate the exact line where it crashes. Use "\n" at the end to flush the output, otherwise it won't print the line during crash:
qDebug() << "...text...\n";
03-28-2013 02:42 AM
03-28-2013 08:39 AM - edited 03-28-2013 08:47 AM
I believe my statement was correct. ![]()
The application will take the ownership of navigationPane, not the qml object:
Application::instance()->setScene(navigationPane);
Qml object's parent is set to 'this' (App class instance) and will be destroyed only when it's parent is destroyed:
QmlDocument *qml = QmlDocument::create("asset:///Primary.qml").parent(this);
So when the function is called second time, the previous 'qml' instance will still exist because it's parent (the App class instance) still exists. But a new qml object instance will also be created. These instances will accumulate with every function call unless deleted manually.
03-28-2013 08:51 AM - edited 03-28-2013 08:53 AM
But the documentation says that when you call Application::instance()->setScene(...), the previous scene (a Page or whatever) will be deleted, so you don't need to delete it manually in this case.
Where in the documentation that says: "the Qml object will be destroyed only when it's parent is destroyed"?
03-28-2013 09:06 AM
That's right, the scene will be deleted. But QmlDocument instance will not be deleted. It's a different object and it isn't passed to setScene, so it won't take the ownership of the object. QmlDocument is used as an interface template to instantiate a scene (NavigationPane in this case), and it's owner is App class.
The parent-child relationship between QObjects is a basic Qt mechanism which applies to all classes. When a parent is assigned to a class, the class will be automatically destroyed when it's parent is destroyed. And in the code above QmlDocument's parent is explicitly set to 'this' (App class instance).
http://doc.qt.digia.com/4.7/objecttrees.html
03-28-2013 09:25 AM
03-28-2013 05:11 PM
QmlDocument doesn't contain the components, it represents a QML file. Multiple instances of root object can be instantiated from single QmlDocument. This page contains more detailed information:
http://developer.blackberry.com/cascades/reference
After first call to setScene the ownership of root object is transferred to the application.
findChild() returns pointers to objects in a tree where the root object (NavPane) is now owned by application.
These pointers will become invalid if the objects are destroyed.
If you create another object tree from QmlDocument and pass the root object to setScene, the application deletes it's previous object tree (because it owned the root object). At this point all previously obtained pointers will become invalid. Referencing them will result in undefined behavior. Sometimes the app will crash.
You can create multiple object trees and swap them by calling setScene, but to prevent application from destroying the previous tree, reset the parent of it's root component (or set it to another object) before reassigning the scene so it's not deleted by the application. However, this is rarely needed and usually can be done some other way.
In other words, QmlDocument is only needed for instantiating component trees. It doesn't own these trees.
03-28-2013 08:29 PM
I tried what you said.. and it still crashes.
It could be a different reason but definitely switching QML document is causing crashing issue.
I gave up and used NavigationPane instead of deleting the qml and loading a new one.
03-29-2013 04:51 PM
First of all, you guys sorta de-railed this topic... but anyways..
I have to agree with Zmey... What you're talking about is the AbstractPane object being deleted when a new setScene is done... The QmlDocument object is different...
Anyways, having said that, testinz you should use 2 different QmlDocument objects to distinguish between the Main and the Secondary... Something like .. qmlMain and qmlSecondary...
In the opposing functions you should check those objects to see if they exist and delete them when you do a new setScene... As in...
Main:
if the Secondary qml exists, delete it and you change the page...
Secondary:
if the Main qml exists, delete it and you change the page...