【问题标题】:Class_Terminate not firing on object from formClass_Terminate 未从表单中触发对象
【发布时间】:2019-03-31 08:30:03
【问题描述】:

我有一个非常简单的表单,它使用一个非常简单的类来处理一些事情。而那个类有一个Class_Terminate 子来清理自己。但是,当表单关闭时,它似乎并没有被触发。

MCVE:

Form 1,一个名为 Text0 的文本框,没有其他控件

Private myClass1 As Class1

Private Sub Form_Load()
    Set myClass1 = New Class1
    myClass1.InitForm Me
End Sub

类 Class1

Public theForm As Form
Private WithEvents SomeTextbox As TextBox
Public Sub InitForm(frm As Form)
    Set theForm = frm
    Set SomeTextbox = frm.Text0
End Sub
Private Sub Class_Terminate()
    MsgBox "Class1 terminated succesfully"
End Sub

但是,当我关闭表单时,类终止处理程序不会触发。

我尝试取消设置类中的 Form 对象:

Private Sub Form_Unload(Cancel As Integer)
    Set myClass1.theForm = Nothing
End Sub

但随之而来的是混乱:类终止处理程序在关闭表单后触发,但之后立即访问硬崩溃而没有任何错误消息!

【问题讨论】:

    标签: vba ms-access


    【解决方案1】:

    当您关闭表单时,Access 不会优雅地清理表单对象。

    这意味着:如果一个对象具有对表单的开放引用,则该表单对象将持续存在。只有在没有对它的引用时,它才能被垃圾收集器删除。

    表单的第一个版本造成​​了内存泄漏:表单对象Form_Form1 引用了Class1(通过MyClass1 变量),Class1 通过@ 引用了表单对象987654326@ 变量。这导致了参考循环。终止处理程序没有触发,因为该类从未终止,它无限期地保留在内存中,关闭并重新打开表单只是打开了该类的一个新实例。

    第二个版本导致了一个问题:当引用循环被破坏时,对Form1的引用首先被释放(因为在Form1上仍然有对Class1的引用),导致垃圾收集器清理它, 然后对Class1 的引用被释放,垃圾收集器试图清理Class1,包括文本框对象SomeTextbox,导致访问硬崩溃,因为表单对象已经被清理并且文本框对象无效。

    解决方案是通过首先删除对Class1 的所有引用来打破引用循环。这不会导致崩溃。

    Private Sub Form_Unload(Cancel As Integer)
        Set myClass1 = Nothing
    End Sub
    

    这会导致垃圾收集器首先清理 Class1 实例,释放对 Text0 的引用,然后清理表单对象,因为没有人打开对它的引用。

    【讨论】:

    • 好奇this 是否也能成为解决方案
    • @MathieuGuindon 仅当您不使用 WithEvents 时才会这样做。如果我理解正确,您将无法使用弱引用收听事件。如果你只为表单对象实现它,你会发生崩溃,因为表单首先被释放,然后是包含对表单上文本框对象的引用的类。如果你使用对Class1 类的弱引用,它会在它应该被释放之前被释放。
    猜你喜欢
    • 2010-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多