質問

Suppose I have two classes, a < matlab.mixin.Copyable and b < handle.

Here's 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

and b:

classdef b < handle
    events
        bEvent
    end

    methods
        function obj = b

        end

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

end

I use saveobj in a to delete the listener upon save. I will manually re-instantiate a listener when I load the classes later.

a inherits from matlab.mixin.Copyable so I can do a copy during the saveobj operation - this way I can make a copy of the original object and change it, without affecting the original, and then save that to a MAT-file. (Supposedly - this is where my question is going.)


Now I run the following at the command line:

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

Everything works. Now, let's save:

>> save ab alice bob

and try to raise the event again:

>> bob.raiseEvent
% NOTHING HAPPENS!

Turns out the listener is gone!

>> alice.hListener
handle to deleted listener

What is going on here? Why is the listener object shared between sobj and obj in the saveobj method?

役に立ちましたか?

解決

In researching this question I discovered the answer. I figured I'd add to the body of knowledge around these parts.

Per the documentation for matlab.mixin.Copyable,

Given a call to the matlab.mixin.Copyable copy method of the form:

B = copy(A);

Under the following conditions, produces the described results:

A has dynamic properties — copy does not copy dynamic properties. You can implement dynamic-property copying in the subclass if needed.

A has no non-Dependent properties — copy creates a new object with no property values without calling the class constructor to avoid introducing side effects.

A contains deleted handles — copy creates deleted handles of the same class in the output array.

A has attached listeners — copy does not copy listeners. (emphasis added)

A contains objects of enumeration classes — Enumeration classes cannot subclass matlab.mixin.Copyable.

A delete method calls copycopy creates a legitimate copy, obeying all the behaviors that apply in any other usage.

What I took this to mean originally was that a copy call would skip over a property whose value is a listener handle. Apparently what it means is that rather than skipping the property altogether, copy makes a reference to the original listener object, i.e., it copies the handle to the listener but not the listener itself.

Of course, when you load the copied object and it has that reference to listener, it'll complain:

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.

The easiest thing to do, then, is to modify saveobj:

function sobj = saveobj(obj)
    sobj = copy(obj);
        
    sobj.hListener = [];
end

Here, I don't explicitly call delete on the listener, as this would delete the actual object. Instead, I just clear the reference to that object.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top