如何在iOS应用程序中正确使用setNeedsDisplayInRect?
我在Yosemite 10.10.5和Xcode 7上,使用Swift制作了一款针对iOS 8及以上版本的游戏 编辑:更多可能有用的细节:这是一款2D益智/街机游戏,玩家在游戏中移动石头以匹配它们。根本没有3D渲染。画画已经太慢了,我甚至还没有看到碎片爆炸。还有一个级别的淡入,非常令人担忧。但到目前为止,这些都在模拟器上。我还没有一台真正的iPhone可以测试,我打赌实际的设备至少会快一点 我有自己的Draw2D类,它是UIView的一种类型,设置如中所示。我有一个NSTimer,它在Draw2D中启动以下调用链:如何在iOS应用程序中正确使用setNeedsDisplayInRect?,ios,swift,xcode7,Ios,Swift,Xcode7,我在Yosemite 10.10.5和Xcode 7上,使用Swift制作了一款针对iOS 8及以上版本的游戏 编辑:更多可能有用的细节:这是一款2D益智/街机游戏,玩家在游戏中移动石头以匹配它们。根本没有3D渲染。画画已经太慢了,我甚至还没有看到碎片爆炸。还有一个级别的淡入,非常令人担忧。但到目前为止,这些都在模拟器上。我还没有一台真正的iPhone可以测试,我打赌实际的设备至少会快一点 我有自己的Draw2D类,它是UIView的一种类型,设置如中所示。我有一个NSTimer,它在Draw2
[setNeedsDisplay];//它调用drawRect,这是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)];
}
但是,我不知道脏矩形的内置列表的名称。我发现说方法名是getrectsbeingdraw
,但那是针对MacOSX的。它在iOS中不存在
有人能帮我吗?我做得对吗?我对Mac和iOS还是相当陌生。如果可能的话,你应该避免覆盖drawRect
。现有的视图/技术利用任何硬件功能使事情比在图形环境中手动绘制快得多,包括缓冲视图内容、使用GPU等。这在“iOS视图编程指南”中重复了很多次
如果你有一个背景和其他对象在上面,你可能应该使用单独的视图或图层,而不是重画它们
您还可以考虑诸如SpriteKit、ScEnKIT、OpenGL ES等的技术
除此之外,我不太确定我是否理解你的问题。调用setNeedsDisplayInRect
时,它会将该矩形添加到需要重新绘制的矩形中(可能与列表中已有的矩形合并)drawRect:
稍后将被调用,一次绘制一个矩形
setNeedsDisplayInRect
/drawRect:
分离的全部目的是确保将重画视图给定部分的多个请求合并在一起,并且每个重画周期只进行一次绘制
您不应该在drawRect:
中调用您的scr\u步骤
方法,因为它可能在一个循环重画循环中被多次调用。这一点在“iOS视图编程指南”(重点内容)中有明确说明:
drawRect:方法的实现应该只执行一个操作
事情:画你的内容此方法不是要更新的位置
您的应用程序的数据结构或执行任何不相关的任务
到绘图。它应该配置绘图环境,绘制
内容,并尽快退出。如果您的drawRect:method
可能会经常打电话,你应该尽你所能
优化绘图代码,每次尽可能少地绘图
方法被调用
关于剪辑,drawRect
的文档说明:
应将任何图形限制为在矩形中指定的矩形
参数此外,如果视图的不透明属性设置为
是的,drawRect:方法必须完全填充指定的矩形
内容不透明
不知道您的视图显示了什么,您调用的各种方法做了什么,实际需要时间做什么,很难提供更多关于您可以做什么的见解。根据您的实际需要提供更多详细信息,我们可能会提供帮助。好的,我通过让NSTimer调用scr_run_gameloop{sc来拆分更新和绘制代码