9

我想我已经接近理解Mono GC 和 ObjC 引用计数是如何一起存在的。

它的工作方式是,当本机对象的引用计数为 1 时,我们不会阻止托管实例进行垃圾收集。一旦引用计数增加到 1 以上,我们就会阻止托管实例被垃圾收集。

这是因为托管对象可能包含用户状态。对于镜像对应本机对象的托管对象(例如托管 UIView 实例),MonoTouch 知道该实例不能包含任何状态,因此只要没有托管代码引用托管实例,GC 就可以收集它。如果稍后需要托管实例,我们只需创建一个新实例。

因此,如果我创建一个CustomButton继承的UIButton,将其作为子视图添加到我的View,让托管引用滑出范围然后运行 ​​GC,这个托管 CustomButton仍然没有资格收集。

为什么不能收藏?当然,它可能具有类似属性的托管状态,但是如果托管对象没有与它的链接,那么谁在乎这个状态呢?它也可能消失,为什么不能呢?

我在想一个可能的原因:订阅CustomButton事件不会让 GC 保持活动状态,因此当对象被收集时,事件会停止触发。这可能会导致意外行为。

它是否正确?即使没有人链接它,是否还有其他原因可以使托管对象保持活动状态?

4

1 回答 1

8

为什么不能收藏?当然,它可能具有类似属性的托管状态,但是如果托管对象没有与它的链接,那么谁在乎这个状态呢?它也可能消失,为什么不能呢?

本机代码可能具有对该对象的引用,这可能会导致该对象稍后再次出现在托管代码中。

我相信一个代码示例可以说明会发生什么:

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 数组会自动缓存在托管代码中 - 但通常情况并非如此。

于 2012-10-25T09:02:22.037 回答