一、从线程安全方面考虑
在UIKit里面很多类都是被修饰为nonatomic,这意味着它们不能在多线程的环境下工作,而对于UIKit这样一个庞大的框架,将其所有属性都设计为线程安全是不现实的,这可不仅仅是简单的将nonatomic改成atomic或者是加锁解锁的操作。
假设能够异步设置view的属性,那我们究竟是希望这些改动能够同时生效,还是按照各自runloop的进度去改变这个view的属性呢?
假设UITableView在其他线程去移除了一个cell,而在另一个线程却对这个cell所在的index进行一些操作,这时候可能就会引发crash。
如果在后台线程移除了一个view,这个时候runloop周期还没有完结,用户在主线程点击了这个“将要”消失的view,那么究竟该不该响应事件?在哪条线程进行响应?
二、Runloop 与绘图循环
UIApplication在主线程所初始化的Runloop我们称为Main Runloop,它负责处理app存活期间的大部分事件,如用户交互等,它一直处于不断处理事件和休眠的循环之中,以确保能尽快的将用户事件传递给GPU进行渲染,使用户行为能够得到响应,画面之所以能够得到不断刷新也是因为Main Runloop在驱动着。
而每一个view的变化的修改并不是立刻变化,相反的会在当前run loop的结束的时候统一进行重绘,这样设计的目的是为了能够在一个runloop里面处理好所有需要变化的view,包括resize、hide、reposition等等,所有view的改变都能在同一时间生效,这样能够更高效的处理绘制,这个机制被称为绘图循环(View Drawing Cycle)。
假设这个时候我们应用了我们的魔法UIKit,并愉快的在一条后台线程操作UI,但当我们需要对设备进行旋转并重新布局的时候,问题来了,因为各个线程之间不同步,这时候各个view修改的请求时机是零碎的,所以所有的旋转变化并不能在Main Runloop的一个runloop里面处理完,这就导致设备旋转之后还有一些view迟迟没有旋转。