为什么我的监听器在saveobj()时被删除?

时间:2014-04-10 20:29:20

标签: matlab listener

假设我有两个类a < matlab.mixin.Copyableb < handle

此处a

classdef a < matlab.mixin.Copyable
    properties
        hListener
    end

    methods
        function obj = a(b)
            obj.newListener(b);
        end

        function newListener(obj, b)
            obj.hListener = addlistener(b, 'bEvent', @(o,e) disp('Received bEvent'));
        end

        function sobj = saveobj(obj)
            sobj = copy(obj);

            delete(sobj.hListener);
            sobj.hListener = [];
        end

    end
end

b

classdef b < handle
    events
        bEvent
    end

    methods
        function obj = b

        end

        function raiseEvent(obj)
            notify(obj, 'bEvent');
        end
    end

end

我在saveobj中使用a来保存时删除侦听器。我稍后加载类时会手动重新实例化一个监听器。

a继承自matlab.mixin.Copyable,因此我可以在copy操作期间执行saveobj - 这样我就可以复制原始对象并对其进行更改影响原始,然后将其保存到MAT文件。 (据说 - 这是我的问题所在。)


现在我在命令行运行以下命令:

>> bob = b; alice = a(bob);
>> bob.raiseEvent
Received bEvent

一切正常。现在,让我们保存:

>> save ab alice bob

并尝试再次举起活动:

>> bob.raiseEvent
% NOTHING HAPPENS!

原来听众已经走了!

>> alice.hListener
handle to deleted listener

这里发生了什么?为什么在listener方法中sobjobj之间共享了saveobj个对象?

1 个答案:

答案 0 :(得分:1)

在研究这个问题时,我发现了答案。我想我会在这些部分周围增加知识体系。

根据documentation for matlab.mixin.Copyable

  

调用表格的matlab.mixin.Copyable复制方法:

     

B = copy(A);

     

在以下条件下,产生描述的结果:

     

A具有动态属性 - copy不会复制动态属性。如果需要,您可以在子类中实现动态属性复制。

     

A没有非依赖属性 - copy创建一个没有属性值的新对象,而不调用类构造函数以避免引入副作用。

     

A包含已删除的句柄 - copy在输出数组中创建同一类的已删除句柄。

     

A附加了听众 - copy不会复制听众。 (强调添加)

     

A包含枚举类的对象 - 枚举类不能继承matlab.mixin.Copyable

     

A删除方法调用copy - copy创建合法副本,遵守适用于任何其他用法的所有行为。

我最初的意思是copy调用会跳过一个值为侦听器句柄的属性。显然它的意思是,copy不是完全跳过属性,而是引用原始的listener对象,即它将句柄复制到监听器而不是监听器本身。

当然,当您load复制的对象并且它具有对侦听器的引用时,它会抱怨:

Warning: Cannot load an object of class 'listener':
 No matching constructor signature found. 
Warning: During load:
 An invalid default object has been detected while loading a heterogeneous array of
 class event.listener. An empty array of class event.listener will be returned.

最简单的方法是修改saveobj

function sobj = saveobj(obj)
    sobj = copy(obj);

    sobj.hListener = [];
end

在这里,我没有在监听器上显式调用delete,因为这会删除实际对象。相反,我只是清除对该对象的引用。