Monotouch和catiledlayer

时间:2016-05-31 17:40:15

标签: ios xamarin.ios sigsegv catiledlayer pdf-viewer

我的一个老问题与在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 px的巨大张量)

    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 ();

        });
    }

1 个答案:

答案 0 :(得分:2)

Apple的示例代码并不是很好。查看tiled view的来源,我看不到将图层委托设置为nil的位置。在引擎盖下,CATiledLayer创建一个队列以在后台调用平铺渲染。这可以导致比赛,并且解决这个问题的一种方法是明确禁止委托。实验表明,这有时会阻塞,因此预计会有一些性能下降。是的,这是一个错误,你应该file a radar - 我多年前这样做了。

我正在开发一个商业PDF SDK(我们有一个非常受欢迎的Xamarin wrapper),我们已离开CATiledLayer年前了。它是一个相对简单的解决方案,但PDF的本质是渲染一个部分,一个人必须遍历整个渲染树 - 它并不总是很容易弄清楚屏幕上有什么,什么不是。 Apple的渲染器正在做一个好的工作并且性能还可以,但是如果你渲染成一个图像然后在用户滚动时移动它/重新渲染,你将获得更好的性能。 (当然,这对于记忆力来说更难以处理,特别是在视网膜屏幕上。)

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