1

我开始真正体会到通过 DMS 语言使用对象在 DigitalMicrograph 环境中部署给定应用程序的好处。面向对象的方法为使用涉及协作对象的可重用设计模式打开了大门,例如模型-视图-控制器(MVC)。然而,由于使用自动引用计数来管理它们的生命周期,DM 中的对象似乎非常不稳定。为了使 MVC 三重奏或任何其他协作对象集能够存活足够长的时间以发挥作用,它们中的至少一个必须植根于由 DM 应用程序管理的非易失性对象中。到目前为止,我在 DM 中遇到的唯一此类对象是基于 UIFrame 类的对象(即无模式对话框和 UI 调色板)。对于 MVC 实现,这很好,因为将 View 实现为 UIFrame 对象是有意义的。只是有点不合常规,因为 View 对象成为保持 MVC 三重奏活动和运行的根对象。通常它是根植于应用程序并管理模型和视图对象的控制器对象。但是不涉及 UI 的设计模式呢?是否有任何(可接受的)方法可以在不将它们植根于 UIFrame 对象的情况下为一组协作对象提供持久性?是否有其他基于应用程序的对象类型可以用于此目的?由于不可避免的内存泄漏风险,我认为设置参考周期不是一种可接受的方法。s 只是有点不合常规,因为 View 对象成为保持 MVC 三重奏活动和运行的根对象。通常它是根植于应用程序并管理模型和视图对象的控制器对象。但是不涉及 UI 的设计模式呢?是否有任何(可接受的)方法可以在不将它们植根于 UIFrame 对象的情况下为一组协作对象提供持久性?是否有其他基于应用程序的对象类型可以用于此目的?由于不可避免的内存泄漏风险,我认为设置参考周期不是一种可接受的方法。s 只是有点不合常规,因为 View 对象成为保持 MVC 三重奏活动和运行的根对象。通常它是根植于应用程序并管理模型和视图对象的控制器对象。但是不涉及 UI 的设计模式呢?是否有任何(可接受的)方法可以在不将它们植根于 UIFrame 对象的情况下为一组协作对象提供持久性?是否有其他基于应用程序的对象类型可以用于此目的?由于不可避免的内存泄漏风险,我认为设置参考周期不是一种可接受的方法。但是不涉及 UI 的设计模式呢?是否有任何(可接受的)方法可以在不将它们植根于 UIFrame 对象的情况下为一组协作对象提供持久性?是否有其他基于应用程序的对象类型可以用于此目的?由于不可避免的内存泄漏风险,我认为设置参考周期不是一种可接受的方法。但是不涉及 UI 的设计模式呢?是否有任何(可接受的)方法可以在不将它们植根于 UIFrame 对象的情况下为一组协作对象提供持久性?是否有其他基于应用程序的对象类型可以用于此目的?由于不可避免的内存泄漏风险,我认为设置参考周期不是一种可接受的方法。

4

3 回答 3

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" )
}
于 2014-11-20T22:32:59.070 回答
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()
}
于 2014-11-20T22:22:50.350 回答
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()
}
于 2014-11-20T22:11:48.463 回答