В архитектуре M C взаимные ссылки вызывают утечки памяти. Как мне изменить хорошую дизайнерскую программу? - PullRequest
0 голосов
/ 20 марта 2020

Нажмите кнопку, QTabWidget добавит вкладку (объект пациента).

Вот как я ее сконструировал.

Сначала модель запрашивает у сети вызов метода пациента после получения данных. для отображения данных.

Во-вторых, пациент будет активно использовать данные в модели.

Итак, я определил self.model = Model () и self.view = view, но это создало проблему. Пациент и модель относятся друг к другу, что приведет к утечке памяти. Поэтому, когда я закрыл вкладку, мне пришлось удалить Patient.model. Атрибуты, чтобы они больше не ссылались друг на друга, и проблема утечек памяти была решена.

Однако в моем проекте у меня есть много случаев, когда представление и модель ссылаются друг на друга. Мне нужно найти их все, а затем закрыть отношения между ними при закрытии вкладки. Я думаю, что этот дизайн немного слаб на утечки памяти. Можете ли вы дать мне несколько лучших дизайнерских предложений? Большое спасибо.

import sys
from PyQt4 import QtGui
from PyQt4.QtGui import QTabWidget, QHBoxLayout, QWidget, QPushButton


class Model(object):
    def __init__(self, view):
        self.view = view


class Patient(QWidget):
    def __init__(self):
        super(Patient, self).__init__()
        self.model = Model(self)
        self.data = [map(lambda x: {'name': 'ken'}, [x for x in range(10000000)])]


class Tab(QTabWidget):
    def __init__(self):
        super(Tab, self).__init__()
        self.setTabsClosable(True)
        self.tabCloseRequested.connect(self.delete)

    def add(self):
        self.addTab(Patient(), 'name')

    def delete(self, index):
        patient = self.widget(index)
        self.removeTab(index)

        import sip
        sip.delete(patient)
        del patient.model


class Example(QtGui.QWidget):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

    def initUI(self):
        self.hbox = QHBoxLayout()
        self.setLayout(self.hbox)

        self.tab = Tab()
        self.hbox.addWidget(self.tab)

        btn = QPushButton()
        btn.clicked.connect(self.click)
        self.hbox.addWidget(btn)

        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle("PyQt")
        self.show()

    def click(self):
        self.tab.add()


def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

1 Ответ

1 голос
/ 21 марта 2020

Если вы всегда используете классы Модель и Пациент, вы можете использовать сигнал destroyed(), чтобы получать уведомления при удалении виджета, и удалять модель.

С deleteLater() также заботится об отключении всех слотов, связанных с уничтожающим объектом, метод не может быть вызван в его собственном экземпляре. Чтобы обойти это, использование лямбды может решить проблему.

class Patient(QWidget):
    def __init__(self):
        super(Patient, self).__init__()
        self.model = Model(self)
        self.data = [map(lambda x: {'name': 'ken'}, [x for x in range(10000000)])]
        self.destroyed.connect(lambda: self.aboutToBeDeleted())

    def aboutToBeDeleted(self):
        del self.model


class Tab(QTabWidget):
    #...
    def delete(self, index):
        patient = self.widget(index)
        self.removeTab(index)
        patient.deleteLater()

Это должно позаботиться обо всем, включая отключение всех слотов и сигналов, связанных с patient. Вызова deleteLater() также должно быть достаточно, вместо использования sip.delete (который, я считаю, в любом случае выполняется с помощью deleteLater).

...