当前位置:  开发笔记 > IOS > 正文

如何正确使用setNeedsDisplayInRect for iOS应用程序?

如何解决《如何正确使用setNeedsDisplayInRectforiOS应用程序?》经验,为你挑选了1个好方法。

我在Yosemite 10.10.5和Xcode 7上,使用Swift制作一款针对iOS 8及以上版本的游戏.

编辑:可能有用的更多细节:这是一个2D拼图/街机游戏,玩家可以移动石头来匹配它们.根本没有3D渲染.绘图已经太慢了,我还没有得到碎片爆炸.还有一个淡入淡出的水平,非常令人担忧.但到目前为止,这一切都在模拟器上.我还没有真正用iPhone测试,我打赌实际的设备至少要快一点.

我有自己的Draw2D类,它是一种UIView,在本教程中设置.我有一个NSTimer,它在Draw2D中启动以下调用链:

[setNeedsDisplay]; // which calls drawRect, which is the master draw function of Draw2D

drawRect(rect: CGRect)
{
  scr_step(); // the master update function, which loops thru all objects and calls their individual update functions. I put it here so that updating and drawing are always in sync

  CNT = UIGraphicsGetCurrentContext(); // get the curret drawing context

  switch (Realm) // based on what realm im in, call the draw function for that realm
  {
    case rlm.intro: scr_draw_intro();
    case rlm.mm: scr_draw_mm();
    case rlm.level: scr_draw_level(); // this in particular loops thru all objects and calls their individual draw functions

    default: return;
  }

  var i = AARR.count - 1; // loop thru my own animation objects and draw them too, note it's iterating backwards because sometimes they destroy themselves
  while (i >= 0)
  {
    let A = AARR[i];
    A.scr_draw();

    i -= 1;
  }
}

所有的绘图都很好,但很慢.

问题是现在我想优化绘图.我想只绘制需要绘图的脏矩形,而不是整个屏幕,这就是setNeedsDisplay正在做的事情.

我找不到任何教程或良好的示例代码.我发现的最接近的是这里的苹果文档,但它没有解释到目前为止如何获得所有脏矩形的列表.它还没有明确说明在每次调用drawRect时是否自动清除脏矩形列表?

它也没有解释我是否必须手动剪辑基于矩形的所有绘图.我在网络上发现了有关这方面的相互矛盾的信息,显然不同的iOS版本做的不同.特别是,如果我要手动剪辑东西,那么我首先看不到苹果核心功能的重点.我可以维护自己的矩形列表,并手动将每个绘图目标矩形与脏矩形进行比较,看看我是否应该绘制任何东西.然而,这将是一个巨大的痛苦,因为我在每个级别都有背景图片,我会在每个移动物体后面画一块.我真正希望的是使用setNeedsDisplayInRect让核心框架对下一个绘制周期中绘制的所有内容进行自动裁剪的正确方法,以便它自动仅绘制背景的一部分以及顶部的移动对象.

所以我尝试了一些实验:首先在我的石头阵列中:

func scr_draw_stone()
{
  // the following 3 lines are new, I added them to try to draw in only dirty rectangles
  if (xvp != xv || yvp != yv) // if the stone's coordinates have changed from its previous coordinates
  {
    MyD.setNeedsDisplayInRect(CGRectMake(x, y, MyD.swc, MyD.shc)); // MyD.swc is Draw2D's current square width in points, maintained to softcode things for different screen sizes.
  }

  MyD.img_stone?.drawInRect(CGRectMake(x, y, MyD.swc, MyD.shc)); // draw the plain stone
  img?.drawInRect(CGRectMake(x, y, MyD.swc, MyD.shc)); // draw the stone's icon
}

这似乎没有任何改变.事情和以前一样缓慢.那么我把它放在括号中:

[MyD.setNeedsDisplayInRect(CGRectMake(x, y, MyD.swc, MyD.shc))];

我不知道括号是做什么的,但我原来的setNeedsDisplay就像他们在教程中所说的那样在括号中.所以我在我的石头物体中试过它,但它也没有效果.

那么我需要做些什么才能使setNeedsDisplayInRect正常工作?

现在,我怀疑在我的主绘制功能中需要一些条件检查,例如:

if (ListOfDirtyRectangles.count == 0)
{
  [setNeedsDisplay]; // just redraw the whole view
}
else
{
  [setNeedsDisplayInRect(ListOfDirtyRecangles)];
}

但是我不知道内置脏矩形列表的名称.我发现这个说方法名称是getRectsBeingDrawn,但这适用于Mac OSX.它在iOS中不存在.

谁能帮我吗?我是否在正确的轨道上?我还是Mac和iOS的新手.



1> jcaron..:

drawRect如果可能的话,你应该真的避免压倒一切.现有的视图/技术利用任何硬件功能使事情比手动绘制图形上下文更快,包括缓冲视图内容,使用GPU等.这在"查看编程指南"中重复多次. iOS版".

如果你有一个背景和其他对象,你可能应该为那些使用单独的视图或图层而不是重绘它们.

您还可以考虑SpriteKit,SceneKit,OpenGL ES等技术.

除此之外,我不太确定我理解你的问题.当你调用时setNeedsDisplayInRect,它会将那个rect添加到需要重绘的那些(可能与列表中已有的矩形合并).drawRect:然后将稍后调用一次一个地绘制这些矩形.

在整点setNeedsDisplayInRect/ drawRect:分离,以确保多个请求重绘视图的给定部分合并到一起,并提请只有每重绘周期发生一次.

您不应该调用您的scr_step方法drawRect:,因为它可能在循环重绘循环中多次调用.这在"适用于iOS的View编程指南"中有明确说明(强调我的):

drawRect:方法的实现应该只做一件事:绘制你的内容.此方法不是更新应用程序的数据结构或执行与绘图无关的任何任务的地方.它应配置绘图环境,绘制内容,并尽快退出.如果你的drawRect:方法可能经常被调用,你应该尽一切可能优化你的绘图代码,并在每次调用方法时尽可能少地绘制.

关于剪辑,文件drawRect说明:

您应该将任何绘图限制为rect参数中指定的矩形.此外,如果视图的opaque属性设置为YES,则drawRect:方法必须使用不透明内容完全填充指定的矩形.

不知道你的观点显示了什么,你调用的各种方法做了什么,实际需要时间,很难提供更多洞察你可以做什么.提供更多细节,以满足您的实际需求,我们也许可以提供帮助.

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有