对象从窗体上没有触发Class_Terminate事件

7

我有一个非常简单的表单,使用一个非常简单的类来处理一些事情。该类具有一个Class_Terminate子程序来清理自身。然而,当关闭表单时,似乎无法触发该子程序。

MCVE:

表单Form1,一个名为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

但是混乱随之而来:关闭表单后,类终止处理程序触发,但紧接着Access在没有任何错误信息的情况下崩溃!
1个回答

7

关闭表单时,Access并不会优雅地清除表单对象。

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

第一个版本的表单创建了内存泄漏:表单对象Form_Form1通过MyClass1变量引用了Class1Class1通过theForm变量又引用了表单对象。这导致了一个引用循环。终止处理程序没有触发,因为该类从未终止,而是无限期地保留在内存中,关闭并重新打开表单只会打开一个新的类实例。

第二个版本出现了问题:虽然断开了引用循环,但首先释放了对Form1的引用(因为Form1上仍有对Class1的引用),导致垃圾回收器清除了它,然后释放了对Class1的引用,并尝试清除Class1,包括文本框对象SomeTextbox,因为表单对象已被清除,所以此时文本框对象已经无效,导致Access崩溃。

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接