该文章属于<简书 — 刘小壮>原创,转载请注明:
<简书 — 刘小壮> http://www.jianshu.com/p/6a222d693d50
视图结构
在iOS当中,视图的结构是以树型结构作为存储的数据结构,这种数据结构有一个很好的优点:
父子关系分明,从根节点出发,通过叶节点向下扩展,同一枝的上一个节点就是下一个节点的superview,下一个节点就是上一个节点的subview;不同枝如果同层,则为兄弟节点。
removeFromSuperview
每一个View都和视图结构和响应者链有直接的关系,但是这篇文章不打算着重的讲这两个特性,而是讲一下removeFromSuperview方法:
Unlinks the receiver from its superview and its window, and removes it from the responder chain.
译:把当前View从它的父View和窗口中移除,同时也把它从响应事件操作的响应者链中移除。
removeFromSuperview,就是一个节点删除的操作,执行这个方法,就等于在树形结构中找到该节点,从树型数据结构中删除该节点及其子节点,而并非只是删除该节点自己。同时,另一个操作就是把该对象从响应者链中移除。
执行removeFromSuperview方法,只是该视图不在屏幕中显示,并没有将该视图从内存中移除。所以我们如果需要使用该视图,不需要再次创建,而是直接addSubview就可以了。
内存管理
经过测试,在ARC的情况下执行removeFromSuperview方法多次也没有问题,因为ARC内存是系统为我们管理的。虽然removeFromSuperview方法在移除视图的过程中会执行一次retain操作,但是在ARC中是没问题的。在MRC中每执行一次removeFromSuperview方法,这个方法内部都会执行一次retain操作,所以在MRC中我们需要注意调用这个方法之后的内存管理的问题。(刚开始我认为执行removeFromSuperview进行的是release操作,经过实验发现居然做了retain操作)
注意点
还有一个需要注意的地方:假设现在有一个ViewA、ViewB、ViewC三个视图,ViewA添加到ViewB之后又要添加到ViewC上面,此时ViewA同时执行了向ViewB、ViewC两个视图addSubview:的操作。但是因为只有一个视图对象,所以只会以最后一次添加的为准,第一次执行的添加到ViewB的操作是无效的。通过打印两个View的子视图可以看到,只有最后执行的添加到ViewC上的操作才是有效的,ViewC才真正拥有了ViewA,而ViewB的子视图是空。
不只是向其他多个页面进行添加操作不会导致崩溃,而且向同一个视图上执行多次添加操作也是没有问题的,并不会导致视图被多次添加的问题。也不需要在添加之前进行removeFromSuperview操作,在MRC中对一个视图执行多次添加操作也不会有问题,引用计数不会发生变化。因为系统在addSubview:方法中进行了一些操作,如果当前视图已经添加到其他视图,会将当前视图从其他视图中移除,然后执行添加操作。如果当前视图已经添加到这个视图中,就不会再次执行添加操作。
注意
1. MRC中调用removeFromSuperview会执行retain操作,这一点估计没有用过MRC的iOS新人都不知道,可以考虑当作面试题