我正在尝试编写一个包裹serial
端口的类来读取传感器:
classdef sensor < handle
properties
Value
s
end
methods
function obj = sensor(port)
obj.s = serial(port);
obj.s.BytesAvailableFcn = @(o,e) obj.getData;
fopen(obj.s);
end
function delete(obj)
disp('called destructor');
try
fclose(obj.s);
delete(obj.s);
end
end
function getData(obj)
obj.Value = fscanf(obj.s, '%d');
end
end
end
当我尝试清除工作区时,析构函数永远不会被调用:
>> foo = sensor('COM1');
>> clear foo % should disp() something!
根据我的previous experiences,仍然必须引用foo
。事实证明它嵌入在串行端口foo.s
:
>> ports = instrfindall;
>> ports.BytesAvailableFcn
ans =
@(o,e)obj.getData
我清除了BytesAvailableFcn
,即
>> ports.BytesAvailableFcn = '';
然后clear all
,我显示了called destructor
。
如何打破此循环引用并让我的析构函数被调用?如果没有调用析构函数,则串口保持绑定。
答案 0 :(得分:2)
问题并不在于你有一个循环引用; MATLAB理论上应该抓住那些。问题是循环引用是通过Java进行的,而MATLAB无法捕获它。
更详细地说 - 您的serial
对象在内部包含一个Java对象,这是捕获与串行端口的连接的真实对象。设置回调时,MATLAB会设置底层Java对象的回调。如果回调是包含串行对象作为属性的对象的方法,那么您有一个循环引用通过底层Java对象。当你调用clear
时,MATLAB会检查循环引用,如果它们全部只在MATLAB中,它会捕获它们,并调用析构函数 - 但它不会捕获它们,因为它通过Java。
一个解决方案是显式调用析构函数,也许这不是太麻烦。
另一种解决方法可能是简单地不将回调作为类的方法 - 也许它可能只是一个常规函数,因为它似乎并不需要任何信息来自主对象本身,而不是对串行对象的引用。如果您希望将所有代码保存在单个文件中,也许您可以将其创建为匿名函数(虽然要小心,因为匿名函数将捕获它创建的工作空间,这取决于您创建它的位置可能包括对主对象的引用,在这种情况下,您将再次获得循环引用。
编辑:Rody是对的 - 我道歉,我读得太快了,并没有注意到getData
实际上设置了Value
属性而不仅仅是返回数据。 Rody在他的回答中的解决方案可能是另一种解决方法,但就像他说 - 哎呀。我只需手动拨打delete
。
答案 1 :(得分:1)
有趣的问题! :)
我找到了一个解决方法,但它不会很漂亮。
obj
的引用。你必须使用一个级别的间接(对Static
方法,否则你会遇到同样的问题)。 Value
属性当然是不可能的,因此,您必须在函数中创建一个全局状态,一个可变参数调用签名和一个{{{}的getter。 1}}属性。 我觉得我已经过度设计了这一点(毕竟是星期五),所以如果有人看到更简单的方法,请纠正我。无论如何,这就是我的意思:
Value
只需....呸。