当我不期待时,我有一个NSObject实例被释放的问题。我有一个NSNumber类型的表单变量,在button1我创建一个实例并设置一个值,在button2中我读取了该值。如果我没有在按钮1中调用retain,那么当我单击button2时,该变量将被释放并且应用程序挂起,添加一个调用keep以使一切正常。
这是在OSX上使用带有firemonkey的Delphi XE6。
这里有一些代码
定义NSNumber
类型的表单变量Fv : NSNumber;
现在添加几个按钮
用于Button1Click
begin
Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0));
ShowMessage(IntToStr(Fv.retainCount)); // value is 1
Fv.retain; // comment out this to make it crash on button2 click
ShowMessage(IntToStr(Fv.retainCount)); // value is 2, or 1 without the retain
end;
for Button2click
begin
ShowMessage(IntToStr(Fv.retainCount)); // value is 1 or crashes without the retain
ShowMessage(FloatToStr(Fv.doubleValue));
end;
现在看来正在发生的事情是在Button1点击结束时,delphi通过递减引用计数来释放Fv - 即它的作用就像它超出了范围。所以为了让Fv流连,我必须添加Fv.retain。如果我单击button2而没有保留,则它会崩溃。
我应该保留 - 我不认为这是必要的,还是我错过了其他的东西?
TIA
答案 0 :(得分:2)
感谢@RudyVelthius和@RemyLebeau让我走上了正确的道路。
问题不在于德尔福问题,而是客观的C问题(至少我对目标C的理解是问题)。
TNSNumber.OCClass.numberWithFloat(4.0)
是一个便利构造函数 - 这意味着它被添加到自动释放池中,并在下次主运行循环执行时释放。
所以我的delphi接口很好,但不幸的是它指向不再存在的东西。保持呼叫保留的自动释放变量。只是为了证明这是调用alloc / init应该修复它的问题。所以
替换
Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0));
与
Fv := TNSNumber.Wrap(TNSNumber.Alloc.initWithDouble(4.0));
并删除保留,一切正常。
从这里https://stackoverflow.com/a/801000/416047规则是
如果返回对象的选择器有单词" new"," alloc", "保留"或"复制"在它,然后你拥有返回的对象,并且 负责在你完成后释放它。
否则你不拥有它,不应该释放它。如果你想 保持对非拥有对象的引用,你应该调用 - [NSObject 保留]在那个实例上。你现在"拥有"那个例子是必须的 因此,当你完成时,在实例上调用 - [NSObject release] 用它。因此,您不拥有 - [NSNumber。]返回的实例 numberWithInt:]并且在完成后不应该调用-release。 如果要将返回的实例保持在当前范围之外 (真正超出当前NSAutoreleasePool的生命周期 例如,你应该 - 保持它。