You are here

Dave's QML Binding Loop Backtrace Printer

Binding loops suck, and they can be hard to fix. I wrote a tool that prints a backtrace of the bindings being updated when a loop occurs. See link at bottom.

About:

QML bindings are a very fast and easy way to write a declarative UI. However it's quite easy to accidentally write an infinite loop.
This can happen if we bind propertyA to affect propertyB and also bind propertyB to affect propertyA, they would constantly update each other.

Consider the following example:

1 import QtQuick 2.0
2 
3 Rectangle {
4     width: childrenRect.width
5     Text {
6        text: parent.width > 10 ? "Hello World" : "Hi"
7     }
8 }

The Rectangle width changes on startup, that changes the text's size, which in turn changes the Rectangle's width. If this was undetected the application would loop forever and eventually crash.
QML prints a warning, and ceases processing, but it's an indication that something is wrong with the logic of your code, and it needs fixing.

However, whilst the loop here is obvious to spot, it can be considerably more complicated when looping through tens of bindings over many many components.

Creating a Tool

The problem with this warning is that on its own is rather unhelpful - trying to find the loop then becomes a manual task of tracing all possible combinations through every bindings that could lead to a short circuit. GDB on its own doesn't help as the C++ backtrace tells us absolutely nothing we can use.

I've created a small script that, using gdb, unwinds the backtrace detecting where the properties changed and then showing the QML code which is responsible.

Simply download here into $PATH and run with

"binding-loop-tracker.py myAppName"

In the case of the loop above we will see output like:

=====Binding loop detected - printing backtrace =====
#0 - file:///home/david/temp/binding_loop.qml:4:12
#1 - file:///home/david/temp/binding_loop.qml:6:15
#2 - file:///home/david/temp/binding_loop.qml:4:12

Which shows which line of QML was being updated when we hit the loop.

It still requires some manual work to follow the trace through, but it's a useful aid and has already helped me in two real world cases that I couldn't resolve manually.

Tags: