【问题标题】:When do I have to keep a reference to my controller or view and when not? See examples我什么时候必须保留对我的控制器或视图的引用,什么时候不需要?查看示例
【发布时间】:2011-09-15 11:24:11
【问题描述】:

在使用 Monotouch 时,我一直想知道两种情况。他们处理保留对UIViewControllerUIView 的引用的要求。

示例一(我在 MT 错误数据库中找到)。它正在实现MKMapViewDelegate,并且从GetViewForAnnotation 返回的视图将被垃圾回收,除非保留托管引用:

class MapViewDelegate : MKMapViewDelegate
{
    public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation)
    {
        var myAnnotation = annotation as MyAnnotation;
        var view = new MKPinAnnotationView (myAnnotation, "myannotation");
        var button = UIButton.FromType (UIButtonType.DetailDisclosure);
        view.RightCalloutAccessoryView = button;

        // I have had this fail as "invalid selector", and also a SIGSEGV crash
        button.TouchDown += delegate {
            Console.WriteLine("I was touched!");
        };

        annotationView = view;

        return annotationView;
    }
}

示例二:如果我使用PresentModalViewController(),我似乎能够在没有托管引用的情况下生存:

ModalSettingsController oSettingsController = new ModalSettingsController ( );
this.PresentModalViewController(oSettingsController, true);

在这种情况下,我从未遇到过 NULL 引用、SIGSEGV 或类似的东西。 看起来在这种情况下“某事”正在保留参考。

我遇到的问题是:如果我要使用纯 C# 环境而没有 ObjC 世界,那么示例一中的代码将毫无问题地工作;视图已创建并分配给其他东西,这意味着存在引用。但由于第一个示例中返回的视图返回到 ObjC 并且没有托管引用,GC 将清除托管版本。这让我有点困惑。我怎样才能确定在哪些情况下我必须保留参考资料,什么时候不需要? 我是否必须查看 Apple 的文档并查看接收器是否保留视图或控制器?

【问题讨论】:

    标签: .net objective-c mono garbage-collection xamarin.ios


    【解决方案1】:

    我是否必须查看 Apple 的文档并查看接收器是否保留视图或控制器?

    没有。一般来说(> 98% 的 API)MonoTouch 将处理所需的引用,让您的 托管 对象在需要时存活。之所以可以这样做,是因为您从应用程序中调用了一些托管 (C#) 代码。例如

     this.PresentModalViewController(oSettingsController, true);
    

    这允许 PresentModalViewController 托管方法在需要时保持对 oSettingsController 的引用(如果需要)。

    那么the issue 的某些 API 是什么?问题是谁在调用 API。例如

    public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation)
    

    如果这是从 C# 中调用的,那么这不会是一个问题,即您的声明 wrt pure C# 是 mostly 正确的。

    然而,它是从 ObjectiveC 调用的,因为我们覆盖了一个继承自本机类型的方法。因此,在这种情况下,一旦方法返回,托管对象 view 就没有(托管)引用(除非您添加一个,例如您的示例#1)。但是本机调用者将保留 视图本机 部分,因此一切都会正常运行...直到您的应用程序尝试返回托管代码.

    由于托管对等体,例如view,已被收集,那么其中管理的所有内容也将被收集(例如按钮)。这就是为什么崩溃经常发生在事件中的原因,例如在您分配给 TouchDown 的委托中。

    话虽如此,我们正在开发一种解决方案,以在未来版本的 MonoTouch 中涵盖这种情况。将自己添加到 c.c. bug report,如果您希望收到进度通知。

    【讨论】:

    • 也许作为通向更好解决方案的桥梁,您可以“滥用” objc_setAssociatedObject 来创建对返回对象的保留引用,从而将其生命周期延长到通常保留未保留引用的对象的生命周期。可以肯定的是,这种方法并不理想,但它已经救了我很多次。 (简而言之:与保留策略关联的对象将在与其关联的对象被释放时被释放。您可以(ab)使用它来有效地将一个对象的生命周期延长到至少与另一个对象的生命周期一样长。 )
    • 感谢您的详细解释。所以一般来说,这意味着:在没有参考保留的情况下尝试。 Monotouch 负责处理它。如果它有问题,它应该在模拟器中崩溃,因为 GC 在模拟器中不断触发。如果它崩溃,请检查 casuse 是否是从 ObjC 世界调用的方法并相应地添加引用。
    • 克鲁梅勒:是的。总是假设 MT 做到了(它非常好,应该会变得更好:-)。如果失败,请尝试确定托管对象的生命周期(以及本机对等点的生命周期)并“使它们匹配”。如有疑问,请在 bugzilla.xamarin.com 上提出问题并附上测试用例。
    • ipmcc:感谢您的建议,已经讨论过类似的想法,但我会确保(我将复制/粘贴您对错误报告的评论)这一点不会被忽视。
    猜你喜欢
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2013-10-23
    • 1970-01-01
    • 2021-08-16
    • 1970-01-01
    相关资源
    最近更新 更多