【问题标题】:Monotouch and catiledlayerMonotouch 和 catiledlayer
【发布时间】:2016-05-31 17:40:14
【问题描述】:

我的一个老问题与在 monotouch 中查看 pdf 文件有关(我设法做到了这一点)。 Port of the iOS pdf viewer for xamarin

我的问题如下:如果我开始关闭并打开一个 pdf 视图(带有 catiledlayer 的视图)真的很快,而且我的应用程序经常崩溃:

Got a SIGSEGV while executing native code. This usually indicates a fatal error in the mono runtime or one of the native libraries used by your application.

在互联网上搜索了几天后,我发现一个帖子说的是:正在清理图像后台存储,这是导致错误的原因。


编辑: 好的,我得出的结论是我的应用程序正在清理内存并且我的指针正在变成空值。我调用了 Gc.Collect() 几次,这似乎是问题的根源。

我已经删除了对 GC.Collect() 的所有调用,并且我目前正在运行压力测试,并将在发现问题后进行更新。

在运行了更多测试后,我发现:

  • 错误似乎来自TiledLayerDelegate : CALayerDelegate 类。

  • 应用程序仅在方法Dispose from CALayerDelegate is called 时崩溃,将方法覆盖为空似乎可以防止应用程序崩溃。

  • 运行应用程序似乎不再引起任何问题。很明显,CALayerDelegate 的 Dispose 方法确实出了问题。

  • 最后发现:像猴子一样运行应用程序往往会使应用程序升温。我认为这是由于 pdf 页面的密集渲染(它们是大约 4,000 X 3,000 像素的巨大纸张)

    protected override void Dispose (bool disposing)
    {
      try{
          view = null;
          GC.Collect (2);
          //base.Dispose (disposing);
      }catch(Exception e) {
        //System.Console.Write(e);
      }
    }
    

现在最重要的是,我只是想知道手机发热是否真的像我假设的那样只是 CPU 渲染工作表并且是正常的。有没有人知道如何最好地处理 Dispose 覆盖?

最后一次编辑:对于任何想要防止崩溃的人来说,这是我最后一个版本的图层视图类的样子。

public class TiledPdfView : UIView {
    CATiledLayer tiledLayer;

    public TiledPdfView (CGRect frame, float scale)
        : base (frame)
    {
        tiledLayer = Layer as CATiledLayer;
        tiledLayer.LevelsOfDetail = 4; //4
        tiledLayer.LevelsOfDetailBias = 4;//4
        tiledLayer.TileSize = new CGSize (1024, 1024);
        // here we still need to implement the delegate
        tiledLayer.Delegate = new TiledLayerDelegate (this);
        Scale = scale;

    }

    public CGPDFPage Page { get; set; }

    public float Scale { get; set; }


    public override void Draw (CGRect rect)
    {
        // empty (on purpose so the delegate will draw)
    }


    [Export ("layerClass")]
    public static Class LayerClass ()
    {
        // instruct that we want a CATileLayer (not the default CALayer) for the Layer property
        return new Class (typeof (CATiledLayer));
    }

    protected override void Dispose (bool disposing)
    {
        Cleanup ();
        base.Dispose (disposing);
    }

    private void Cleanup ()
    {
        InvokeOnMainThread (() => {
            tiledLayer.Delegate = null;
            this.RemoveFromSuperview ();
            this.tiledLayer.RemoveFromSuperLayer ();

        });
    }

【问题讨论】:

    标签: ios xamarin.ios segmentation-fault catiledlayer pdf-viewer


    【解决方案1】:

    Apple 的示例代码并不是很好。查看tiled view 的来源,我看不到您将层委托设置为零的地方。在后台,CATiledLayer 创建了一个队列以在后台调用平铺渲染。这可能会导致竞争,解决此问题的一种方法是明确地取消代表。实验表明,这有时会阻塞,因此预计会出现一些性能下降。是的,这是一个错误,您应该 file a feedback - 我几年前就这样做了。

    我正在开发一个商业 PDF SDK(我们有一个非常受欢迎的Xamarin wrapper),几年前我们离开了CATiledLayer。这是一个相对简单的解决方案,但 PDF 的本质是要渲染一个部分,必须遍历整个渲染树 - 找出屏幕上的内容和不显示的内容并不总是那么容易。 Apple 的渲染器在这方面做得还不错,性能还可以,但是如果您渲染到一个图像中,然后在用户滚动时移动/重新渲染,您将获得更好的性能。 (当然,这对记忆来说更棘手也更难,尤其是在视网膜屏幕上。)

    如果您没有时间离开CATiledLayer,有些人会选择核选项并手动从视图中删除图层。参见例如this question 了解更多详情。

    【讨论】:

    • 指向类似问题的链接对我帮助很大。我仍在运行测试,但目前看来效果很好。
    • 谢谢,我已经控制住了。调试它很痛苦,但现在一切都很好。我总是尽量避免使用商业图书馆,因为从长远来看它们往往非常昂贵。
    • 这完全取决于您的用例和您需要的功能。从长远来看,维护代码也很昂贵,然后你需要这个小特性和那个小特性,然后有这个小错误和那个崩溃,最后你在它上面花费的时间和金钱比许可要多。而且我什至没有谈论机会成本——在您构建一个非常基本的 PDF 查看器时,您可以构建什么?我们一遍又一遍地看到这个故事。但我不知道你的用例,所以也许它是一个快速的一次性应用程序,你真的不需要文本选择或搜索。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 2012-06-20
    相关资源
    最近更新 更多