首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》5.1 运行循环和重绘视图

关灯直达底部

ios应用启动时会开始一个运行循环(run loop)。运行循环的工作是监听事件,例如触摸。当事件发生时,运行循环会为相应的事件找到合适的处理方法。这些处理方法会调用其他方法,而这些方法又会调用更多其他方法,依此类推。只有当这些方法都执行完毕时,控制权才会再次回到运行循环。

当应用将控制权交回给运行循环时,运行循环首先会检查是否有等待重绘的视图(即在当前循环收到过setNeedsDisplay消息的视图),然后向所有等待重绘的视图发送drawRect:消息,最后视图层次结构中所有视图的图层再次组合成一幅完整的图像并绘制到屏幕上。

图5-1是以用户在文本框中输入文字为例,展示视图如何在运行循环中重新绘制自己。

图5-1 视图在运行循环中重新绘制自己

ios做了两方面优化来保证用户界面的流畅性——不重绘显示的内容没有改变的视图;在每次事件处理周期(event handling cycle)中只发送一次drawRect:消息。在事件处理周期中,视图的属性可能会发生多次改变,如果视图在每次属性改变时都重绘自己,就会减慢界面的响应速度。相反,iOS会在运行循环的最后阶段集中处理所有需要重绘的视图,尤其是对于属性发生多次改变的视图,在每次事件处理周期中只重绘一次。

在Hypnosister应用中,首先,通过控制台的输出信息可以知道,BNRHypnosisView的触摸处理方法已经正确捕获了触摸事件。其次,虽然运行循环在touchesBegan:withEvent:执行完成后再次获得了控制权,但是并没有向BNRHypnosisView发送drawRect:消息。

为了标记视图要重绘,必须向其发送setNeedsDisplay消息。iOS SDK中提供的视图对象会自动在显示的内容发生改变时向自身发送setNeedsDisplay消息,以UILabel对象为例,在某个UILabel对象收到setText:消息后,就会将自己标记为要重绘(因为UILabel对象所显示的文字内容变了,所以必须将自己重新绘制到图层上)。而对自定义的UIView子类,必须手动向其发送setNeedsDisplay消息,如Hypnosister应用中的BNRHypnosisView。

在BNRHypnosisView.m中,为circleColor属性实现自定义的存方法,当circleColor改变时,向视图发送setNeedsDisplay消息。

- (void)setCircleColor:(UIColor *)circleColor

{

_circleColor = circleColor;

[self setNeedsDisplay];

}

再次构建并运行应用,现在可以通过触摸视图改变圆形颜色了。

(还有一种优化方法:只重绘视图的某一区域。可以通过向视图发送setNeedsDisplayInRect:消息标记视图的某一区域要重绘。当视图收到drawRect:消息时,setNeedsDisplayInRect:会将CGRect类型的参数传递给drawRect:,重绘视图的指定区域。但是,随着应用的视图层次结构越来越复杂,计算正确的重绘区域也会越来越困难。通常情况下,不需要手动指定视图的重绘区域,除非绘图代码显着降低了应用性能。)