在使用Monotouch时,我一直想知道两种情况。他们处理了保留对UIViewController
或UIView
。
示例一(我发现在MT bug数据库中)。它正在实现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世界,那么来自示例1的代码可以毫无问题地运行;视图已创建并分配给其他内容,这意味着存在引用。但是,由于第一个示例中返回的视图返回到ObjC并且没有托管引用,因此GC将清除托管版本。这让我有些困惑。我怎么能弄清楚在哪些情况下我必须保留参考,何时不参考? 我是否必须查看Apple的文档并查看收件人是否保留视图或控制器?
答案 0 :(得分:1)
我是否必须查看Apple的文档并查看收件人是否保留视图或控制器?
没有。通常(大约98%的API)MonoTouch将处理所需的引用,以便在需要时让托管对象生效。这可以完成,因为您从应用程序中调用了一些托管(C#)代码。 E.g。
this.PresentModalViewController(oSettingsController, true);
这允许 PresentModalViewController 托管方法在需要时为 oSettingsController 保留引用(如果需要)。
那么the issue与某些API有什么关系?问题是谁在调用API。 E.g。
public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation)
如果这被称为C#形式,则不会出现问题,即您的声明纯 C#mostly正确无误。
然而,它是从 ObjectiveC 调用的,因为我们从继承的本机类型覆盖方法。因此,在这种情况下,托管对象视图在方法返回后没有(托管)引用(除非您添加一个,如示例#1)。但是本机调用者将保留本地部分视图,这样一切都可以工作......直到您的应用程序尝试返回托管代码
自托管对等方以来,例如查看已被收集,然后其中的所有托管也将被收集(例如按钮)。这就是崩溃经常发生在事件中的原因,例如在您分配给 TouchDown 的代理中。
据说我们正在制定解决方案,以便在未来版本的MonoTouch中涵盖此案例。加入c.c.如果您希望获得有关进展的通知,请bug report。