Delphi XE6 ARC on OSX 释放变量
Delphi XE6 ARC on OSX releasing variables
我在意外释放 NSObject 实例时遇到问题。我有一个 NSNumber 类型的表单变量,在 button1 中我创建了一个实例并设置了一个值,在 button2 中我读取了该值。如果我不在按钮 1 中调用 retain,那么当我单击 button2 时,变量将被释放并且应用程序会挂起,添加对 retain 的调用会使一切正常。
这是在 OSX 上使用 Delphi XE6 和 firemonkey。
这是一些代码
定义一个 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;
对于 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,它就会崩溃。
我是否应该保留 - 我认为没有必要,还是我遗漏了其他内容?
蒂亚
感谢@RudyVelthius 和@RemyLebeau 让我走上了正确的道路。
问题不是 delphi 问题而是 objective C 问题(至少我对 objective C 的理解是问题所在)。
TNSNumber.OCClass.numberWithFloat(4.0)
是一个方便的构造函数 - 这意味着它被添加到自动释放池中,并在下次主 运行 循环执行时释放。
所以我的 delphi 界面很好,但不幸的是它指向的东西不再存在。在调用 retain 周围保留一个自动释放变量。只是为了证明这是调用 alloc/init 应该解决的问题。所以
替换
Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0));
和
Fv := TNSNumber.Wrap(TNSNumber.Alloc.initWithDouble(4.0));
并删除保留,一切正常。
从这里 规则是
If the selector returning an object has the word "new", "alloc",
"retain" or "copy" in it, then you own the returned object and are
responsible for releasing it when you are finished.
Otherwise you do not own it and should not release it. If you want to
keep a reference to a non-owned object, you should call -[NSObject
retain] on that instance. You now "own" that instance an must
therefore call -[NSObject release] on the instance when you are done
with it. Thus you do not own the instance returned by -[NSNumber
numberWithInt:] and should not call -release on it when you are done.
If you want to keep the returned instance beyond the current scope
(really beyond the lifetime of the current NSAutoreleasePool
instance), you should -retain it.
我在意外释放 NSObject 实例时遇到问题。我有一个 NSNumber 类型的表单变量,在 button1 中我创建了一个实例并设置了一个值,在 button2 中我读取了该值。如果我不在按钮 1 中调用 retain,那么当我单击 button2 时,变量将被释放并且应用程序会挂起,添加对 retain 的调用会使一切正常。
这是在 OSX 上使用 Delphi XE6 和 firemonkey。
这是一些代码
定义一个 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;
对于 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,它就会崩溃。
我是否应该保留 - 我认为没有必要,还是我遗漏了其他内容?
蒂亚
感谢@RudyVelthius 和@RemyLebeau 让我走上了正确的道路。
问题不是 delphi 问题而是 objective C 问题(至少我对 objective C 的理解是问题所在)。
TNSNumber.OCClass.numberWithFloat(4.0)
是一个方便的构造函数 - 这意味着它被添加到自动释放池中,并在下次主 运行 循环执行时释放。
所以我的 delphi 界面很好,但不幸的是它指向的东西不再存在。在调用 retain 周围保留一个自动释放变量。只是为了证明这是调用 alloc/init 应该解决的问题。所以
替换
Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0));
和
Fv := TNSNumber.Wrap(TNSNumber.Alloc.initWithDouble(4.0));
并删除保留,一切正常。
从这里 规则是
If the selector returning an object has the word "new", "alloc", "retain" or "copy" in it, then you own the returned object and are responsible for releasing it when you are finished.
Otherwise you do not own it and should not release it. If you want to keep a reference to a non-owned object, you should call -[NSObject retain] on that instance. You now "own" that instance an must therefore call -[NSObject release] on the instance when you are done with it. Thus you do not own the instance returned by -[NSNumber numberWithInt:] and should not call -release on it when you are done. If you want to keep the returned instance beyond the current scope (really beyond the lifetime of the current NSAutoreleasePool instance), you should -retain it.