1

我的大部分 UIKitDispose覆盖在它们被破坏之前对其他视图做一些事情:

protected override void Dispose (bool disposing)
{
    if (ScrollView != null) {
        ScrollView.RemoveObserver (this, new NSString ("contentOffset"));
        ScrollView.RemoveObserver (this, new NSString ("contentInset"));
        ScrollView = null;
    }

    base.Dispose (disposing);
}

我最近才意识到,如果is ,Dispose它将在终结器线程上运行。 在这种情况下,将从错误的非 UI 线程调用。disposingfalse
ScrollView.RemoveObserver

在中进行与 UIKit 相关的清理的安全方法是什么Dispose

4

3 回答 3

4

如果 disposing is false,那么最好不要调用该代码。

protected override void Dispose (bool disposing)
{
    if (disposing)
    {
        if (ScrollView != null) {
            ScrollView.RemoveObserver (this, new NSString ("contentOffset"));
            ScrollView.RemoveObserver (this, new NSString ("contentInset"));
            ScrollView = null;
        }
    }
    base.Dispose (disposing);
}

作为对您的问题的更一般的答案-假设此代码在 UIViewController 中-在 ViewDidAppear、ViewDidDisappear 中附加/分离这些观察者可能会更好-然后您可以完全避免此问题。

于 2013-02-05T17:12:02.787 回答
4

Adam Kemp在 Xamarin 论坛上的镜像线程中发布了一个很好的解释。

只有当disposingtrue应该做任何工作。如果是这样, false那么您将被终结器调用,因此访问该其他对象是不安全的。在这种情况下,您应该访问的唯一内容是任何非托管资源(例如IntPtr存储您需要释放的本机分配或需要终止的本机线程)。

这显然提出了何时做你目前在那里做的工作的问题。如果您在视图控制器中,那么您可以使用类似WillDisappear. 如果您在视图中,那么您可以只使用WillMoveToWindow(如果您从窗口中删除,则使用 null 作为窗口调用)。

另一个重要的关于ReleaseDesignerOutlets

ReleaseDesignerOutlets从终结器调用时也不能调用。请记住,在终结器中查看对象引用的任何其他托管对象是不安全的。这些对象可能不再存在。

跳过这是安全的,因为其他每个对象都已经有一个类似的终结器。如果你从不去调用Dispose()它们,那么它们将从终结器线程调用它们的终结器,在这种情况下,它们自己的终结器将调用自己的终结 器,并Dispose(bool)带有 false,这意味着“你正在从终结器调用”。由于本机对象是非托管资源(只是一个 IntPtr),因此他们的Dispose(bool)方法释放对这些本机资源的引用以允许这些本机对象离开内存是安全的。

您实际上可以使用程序集浏览器来查看NSObject's FinalizeDispose(bool)methods 所做的事情来验证我刚刚描述的内容。不管你做什么,永远不要从终结器中访问你的托管资源,这意味着Dispose(bool)当 disposing 参数为 false 时永远不要访问它们。

谢谢亚当!

于 2013-02-06T06:44:43.580 回答
0

你能用吗

InvokeOnMainThread(delegate {....})

杀死 UIKit 的东西?不是 100% 确定它会做你想做的事,但是当你可能在/在不同的线程上时,这是做 UIKit 东西的正常方式。

于 2013-02-06T12:02:55.110 回答