我非常欣赏使用对象通过DMS语言在DigitalMicrograph环境中部署给定应用程序的好处。面向对象的方法打开了使用涉及协作对象的可重用设计模式的大门,例如,模型 - 视图 - 控制器(MVC)。但是,由于使用自动引用计数来管理其生命周期,因此DM中的对象似乎具有高度不稳定性。为了使MVC三元组或任何其他协作对象集合保持足够长的时间以使其有用,它们中的至少一个必须植根于由DM应用程序管理的非易失性对象。到目前为止,我在DM中遇到的唯一这样的对象是基于UIFrame类的对象(即无模式对话框和UI调色板)。对于MVC实现,这很好用,因为将View实现为UIFrame对象是有意义的。它只是有点不同寻常,因为View对象成为保持MVC三重奏活着并运行的根对象。通常,它是Controller对象,它以应用程序为根,管理Model和View对象。但是那些不涉及UI的设计模式呢?是否有任何(可接受的)方法来提供一组协作对象持久性而不将它们植入UIFrame对象中?是否有其他可应用于此目的的应用程序根对象类型?我认为由于不可避免的内存泄漏风险,建立一个参考周期不是一种可接受的方法。
答案 0 :(得分:1)
我可以想出各种方法来获得这种持久性,但首先想到的是将一个对象引入后台线程,如下例所示。如果对象仍然存在,实际的后台线程可以经常检查,并且通过与外部世界共享对象ID,其他对象(不必是持久的)可以访问“锚定”对象。
尽管如此警告:如果你把这些内容保存在内存中,关闭DigitalMicrograph时一定要小心。如果对象挂起了DM想破坏的一些项目,你可能会在最后看到错误或崩溃。
// This is the object "anchored". It will remain in memory, because we launch it on a separate thread.
// On this thread, it loops until a variable is set to false (or until SHIFT is pressed)
Class IPersist : Thread
{
number keepme
IPersist( object self ) { result("created IPersist:"+self.ScriptObjectGetID()+"\n");}
~IPersist( object self ) { result("killed IPersist:"+self.ScriptObjectGetID()+"\n\n\n\n");}
void CallFromOutside( object self ) { Result( "\t IPersist can be used!\n" ); }
void StopFromOutside( object self ) { keepme = 0; }
void RunThread( object self )
{
keepme = 1
Result( "\t Called once at start.\n")
While( keepme && !ShiftDown() ) yield()
Result( "\t Finished.\n")
}
}
// Just and example class used to access the 'anchored' object
Class SomethingElse
{
number keepID
SomethingElse( object self ) { result("created SomethingElse:"+self.ScriptObjectGetID()+"\n");}
~SomethingElse( object self ) { result("killed SomethingElse:"+self.ScriptObjectGetID()+"\n");}
void SetKeepID( object self, number id ) { keepID = id; }
void CallOut( object self )
{
result( "SomethingElse object is accessing CallOut...\n" )
object p = GetScriptObjectFromID( keepID )
if ( p.ScriptObjectIsValid() )
{
p.CallFromOutside()
}
}
void CallStop( object self )
{
result( "SomethingElse object is accessing CallOut...\n" )
object p = GetScriptObjectFromID( keepID )
if ( p.ScriptObjectIsValid() )
{
p.StopFromOutside()
}
}
}
// Main script. Create object on separate thread. Then feed it's ID as "weak reference" into the second object.
{
object ob = Alloc(IPersist)
ob.StartThread()
object other = Alloc(SomethingElse)
other.SetKeepID( ob.ScriptObjectGetID() )
other.CallOut()
If ( TwoButtonDialog( "You can either stop IPerstis now, or by pressing SHIFT later.", "Stop now", "later" ) )
other.CallStop()
}
答案 1 :(得分:1)
另一种方法是让两个对象保持彼此的引用。这是一种通常宁可避免的死锁情况,但为了锚定,它也可以起作用。在您故意释放对象之前,任何对象都不会超出范围。 同样,您有责任发布'当你想要正确关闭系统时的事情。
死锁情况的代码相当渺茫:
class SelfLock
{
object partner
SelfLock( object self ) { result("created SelfLock:"+self.ScriptObjectGetID()+"\n");}
~SelfLock( object self ) { result("killed SelfLock:"+self.ScriptObjectGetID()+"\n");}
void SetPartner(object self, object p) { partner = p; }
void ReleasePartner(object self) { partner = NULL; }
}
{
object p1 = Alloc(SelfLock)
object p2 = Alloc(SelfLock)
p1.SetPartner(p2)
p2.SetPartner(p1)
if ( TwoButtonDialog( "Release partner", "Yes", "No keep locked" ) )
p1.ReleasePartner()
}
答案 2 :(得分:1)
第三种,也是迄今为止最好,最干净的解决方案是将你的对象作为一个“倾听者”来启动。对某些事件。当您正在寻找一个只要DigitalMicrograph打开时应该保持在范围内的对象,它可能最好听取应用程序本身。通过倾听" about_to_close"消息,你也可以获得在关机前正确释放所有资源的理想句柄。代码如下:
从我的3个答案中,我将使用这个答案。 (其他人应该只是说明选项。)
class MyPermanentObject
{
MyPermanentObject( object self ) { result("created MyPermanentObject :"+self.ScriptObjectGetID()+"\n");}
~MyPermanentObject( object self ) { result("killed MyPermanentObject :"+self.ScriptObjectGetID()+"\n");}
void DeInitialize( object self, number eventFlags, object appObj )
{
OKDialog( "The application is closing now. Deinitialize stuff properly!" );
}
}
{
object listener = Alloc( MyPermanentObject )
ApplicationAddEventListener( listener, "application_about_to_close:DeInitialize" )
}