我想我已接近理解how Mono GC and ObjC ref counting live together。
它的工作方式是当本机对象的引用计数为1时,我们不会阻止托管实例进行垃圾回收。 一旦引用计数增加到1以上,我们就会阻止托管实例进行垃圾回收。
这是因为托管对象可能包含用户状态。对于镜像相应本机对象(例如托管UIView实例)的托管对象,MonoTouch知道实例不能包含任何状态,因此只要没有托管代码具有对托管实例的引用,GC就可以收集它。如果稍后需要托管实例,我们只需创建一个新实例。
因此,如果我创建一个继承CustomButton
的{{1}},请将其作为子视图添加到我的UIButton
,让托管参考滑出范围,然后运行GC,此托管 View
仍然没有资格收集。
为什么不收集它?当然它可能有类似属性的管理状态,但是如果没有来自托管对象的链接,谁关心这个状态?它可能也会消失,为什么不能呢?
我正在考虑一个可能的原因:订阅CustomButton
事件不会使GC保持活动状态,因此当收集对象时,事件会停止触发。这可能会导致意外行为。
这是对的吗?是否还有其他原因可以使托管对象保持活动状态,即使没有人链接它?
答案 0 :(得分:7)
为什么不收集它?当然它可能具有类似属性的托管状态,但是如果没有来自托管对象的链接,谁关心这个状态?它可能也会消失,为什么不能呢?
本机代码可能引用了该对象,这可能导致该对象稍后再次重新出现在托管代码中。
我相信代码示例会说明会发生什么:
class MyView : UIView {
public string ImportantSecret;
}
class AppDelegate : UIApplicationDelegate {
UIViewController vc;
public override bool FinishedLaunching (UIApplication app,
NSDictionary options)
{
var myView = new MyView ();
myView.ImportantSecret = "MonoTouchRocks";
vc = new UIViewController ();
vc.View = new UIView ();
vc.View.AddSubView (myView);
// When this method returns the only place where myView is referenced
// is from inside the *native* Subviews collection.
BeginInvokeOnMainThread (() =>
{
Console.WriteLine (((MyView) vc.Subviews [0]).ImportantSecret);
// If the MyView instance was garbage collected and recreated
// automatically at this point, ImportantSecret would be null.
});
}
}
重要说明:此代码仅用于说明GC无法收集可能具有状态的托管对象的原因。这个特定的样本实际上不会忘记重要的秘密,因为Subviews数组会自动缓存在托管代码中 - 但这通常不正确。