luni, 13 ianuarie 2014

Experienţe cu Python şi Qt

Lucrez la un client de Yahoo! Messenger, pe care îl scriu în Qt şi Python. Tocmai am rezolvat un bug funny care mi-a reamintit cât de fâşneţ e Qt când vine vorba de managementul memoriei. Aş spune că e unul chiar violent, având în vedere faptul că acesta dealocă tot ce se poate dealoca şi reutilizează tot ce se poate reutiliza.

Mai demult implementasem descărcarea de avatare folosind clase şi metode din framework-ul Qt. Setam frumuşel un QNetworkAccessManager la care conectam o metodă din clasa mea la semnalul finished, setam şi un QNetworkRequest pentru a-l folosi cu managerul şi îi dădeam bătaie. Doar că metoda mea (cea conectată la semnal) nu era niciodată apelată, ca şi cum cererea nici nu s-ar fi făcut. Ei bine, până nu am adăugat adăugat câte un self. înaintea variabilelor pentru instanţele de QNetworkAccessManager şi cea de QNetworkRequest nu a vrut să meargă treaba nici chip! Qt dealoca aceste obiecte de îndată ce ieşea din metoda mea, aşa că ciu-ciu răspuns. Iar asta de dragul economiei de memorie.

Astăzi într-o metodă făceam ceva de genul
pixmap = QPixmap("ui/resources/no-avatar.png")
if self.image_data:
    pixmap.loadFromData(self.image_data)
return pixmap
 metodă care se apela de mai multe ori. Ideea era să am o imagine implicită pentru avatare, în caz că un user nu are setat unul, iar dacă are să îi afişez avatarul acestuia. Nu vă spun ce distracţie era la mine pe ecran: imagini care se schimbau aparent fără motiv, de fiecare dată când executam diferite acţiuni asupra interfeţei. Ei bine problema e că atunci când apelam prima linie se creea o instanţă de QPixmap conţinând imaginea specificată la iniţializare, iar la apelările ulterioare Qt doar creea un pointer către instanţa creeată de prima dată, de vreme ce oricum avea deja în memorie acea imagine. Ulterior, când se întâmpla ca codul din condiţia if să se execute, imaginea de la pointer-ul meu era schimbată, cauzând toate locurile unde afişam un avatar să "adopte" noua imagine. A luat ceva timp până să dau de capăt problemii.

Deşi se mai întâmplă să dea bătăi de cap, acest management al memoriei e un lucru foarte bun deoarece spală păcatele programatorilor care uneori mai uită să dealoce din obiecte. Sunt curios cum s-ar comporta Qt în C++, de exemplu, într-o situaţie similară cu cele de sus, sau dacă acest management al memoriei vine ca un feature PyQt-only.

1 comentarii :

undergraver spunea...

E doar python-ul. Qt-ul n-are treaba.

De ex aici x se creaza (__init__ chemat) si la iesirea din functie se distruge (se cheama __del__):

def MyFunc():
x = Class() # aici se creaza
# la iesire se distruge