`
jishublog
  • 浏览: 869532 次
文章分类
社区版块
存档分类
最新评论

墨半成霜为您深入剖析UIViewController与UIView(一)

 
阅读更多
如果你对UIViewController的理解仅限于:一个UIViewController 可以push/pop/present到另外一个ViewController,并且给UIView提供容器的话,你可以读读这篇文章了~
如果你对UIView的理解仅限于:UIView是一个将内容呈现给用户的载体的话,你可以读读这篇文章了。

众所周知UIView是基本上是所有控件(用户能看到的内容)的母类(基类)。那么作为一个基类,他的抽象级别是最高的了,也是最简了。我们来看看UIView基类的头文件声明:

<script src="https://code.csdn.net/snippets/766.js" type="text/javascript"></script>




首先我们看到他@了UIEvent,UIWindow,UIViewController,UIColor,UIGestureRecognizer和CALayer,说明任何一个控件在继承UIView的同事,也"认识"了他们,并且我们在API文档中看到这样一句话:
Although there are many good reasons to subclass UIView, it is recommended that you do so only when the basic UIView class or the standard system views do not provide the capabilities that you need. Subclassing requires more work on your part to implement the view and to tune its performance.




即任何可视化的内容都建议你去继承UIView这个母类(你能想到的可见内容是哪些?看看他们的头文件是否都是直接或者间接继承自UIView?能举出反例吗?),如果你非要一意孤行想要自己实现,或者现有的这个基类在某些功能上面不能满足你,那你可能需要花费一大堆工作来完成了(UIView继承自UIResponder,UIResponder继承自NSObject,NSObject已经是OC里面的上帝了,没有父类了),如果你动手能力非常强,当然也可以自己继承NSObject或者UIResponder来实现可视化的Object!。


一路看下来,NSObject在UIResponder父类的基础上添加了一大堆属性和类方法、实例方法。但是与UIButton、UIScrollview、UIlabel等衍生类来讲,即使在这一个层级上多出来了这么多东西,但是他已经是视图级别的最小单位,占用内存最小的类了。

当然,严格意义上来讲,UIView也不算是最小单位,因为UIView的成员:CALayer比他更小,但是如果没有一个UIView来承载他,那么任何Layer的实现都是不能被用户看到的,所以谈到可视化的内容,我们可以理解为CALayer是人的细胞,而UIView是我们的皮肤,如果我们外在的皮肤这个容器,那么细胞是无法单独存在的。

我们先看看他的父类UIResponser做了什么封装?
<script src="https://code.csdn.net/snippets/767.js" type="text/javascript"></script>




这里我们最熟悉的应该属touches系列函数了吧!那么你看,UIView在继承他父类的时候已经继承了这一组实例方法,所以我们自定义任何一个UIView的时候,不需要任何的导入和声明就可以直接联想出来touchesBegan系列函数,就是UIView的功劳,我们只需要去重载父类的实例方法就可以了。下面的两个接口我只想提出一个大家可以了解了解:
<script src="https://code.csdn.net/snippets/768.js" type="text/javascript"></script>


前面两个成员,我们在做自定义键盘的时候就得靠他们!一个是输入法本身,另一个是协助用的,所以我们可以对任何view都可以获取到这两个成员,虽然仅仅在UITextField和UITextView上面调用才有明显的作用。再看下面这个实例方法,从字面上解读是重载输入视图,那么其实作用就相当于在我们重新制定了一个view的inputView之后,键盘不会立刻更新,而只有再下一次获得焦点的时候去更新(这里可以理解为他SDK内部没有发送键盘类型切换通知并且重绘keyboard),所以普通的做法是先resignFirstResponder,然后马上又becomeFirstResponder。而聪明的做法是直接调用:
<script src="https://code.csdn.net/snippets/769.js" type="text/javascript"></script>

如果你现在用的也是前面这种方式,不妨试试调用这个方法,你会上瘾的。


OK,我们摸清楚了UIView的家族史之后,我们再来细看UIView本身的一些特征。私有成员我们就不讨论了,及时你想改也改不了,除非你自己继承NSObject来写一个你自己的UIView 2.0。

首先我们看看这5行:

<script src="https://code.csdn.net/snippets/770.js" type="text/javascript"></script>


makeKeyAndVisible很熟悉对吧?我们记得哪儿调用过?是不是appDelegate中的那个UIWindow调用过呢?

是的,你仔细看看,UIWindow也是UIView的子类,所以这个方法是给我们的window用的,一般来说一个iOS应用只有一个Window,我们在appDelegate中初始化他并让他变为响应的接受者和Z轴最高的window(其他程序也有其他的window,所以我们要让他置顶)。
我在问答板块问过这个问题,这句话的作用是什么,这里我不卖关子了,首先这个方法按词义来讲分为两个目的:makeKey makeVisible
makeKey的作用就在于发送一个全局通知给NSNotificationCenter,对应的其他object好知道这个window现在处于第一优先响应级别。
makeVisible的作用就相当于我们调整他的Z轴,让他处于所有window的顶部,让我们只能看到他。
所以说这样来讲,我发布的那个问题,我说大家的回答老师不够满意,应该能够理解了吧。我们不妨来做个试验,创建一个单视图工程,在默认的VC的视图中拖拽一个textfiled然后直接运行:
效果我就不说了,现在我们来做这样一件事情。
修改appdegate:

<script src="https://code.csdn.net/snippets/771.js" type="text/javascript"></script>



我们再运行下,看看还能看到我们的内容吗?

1961FA86-8EFA-4727-9F03-0F437078C4D9.png

这就是因为window现在只是处于makeKey但是没有visible(可见)。那么不可见,但是我makeKey了,大家肯定要问我怎么知道这个window是不是第一响应啊?
我们不妨来写这样一段代码再次改写这个方法:
<script src="https://code.csdn.net/snippets/772.js" type="text/javascript"></script>



在运行下看看,是不是又出来了?注意这里他提供的make方法只有2个都选,或者只选makekey,没有单独的makeVisible成员方法,但是他有这样一段注释:
<script src="https://code.csdn.net/snippets/773.js" type="text/javascript"></script>


所以单独设置为visible需要显示地调用setHidden:NO来实现。
但是大家再尝试打字,还能打字吗?你会发现不管你怎么按都没有反应。这是因为我们的系统没有收到当前这个window处于可接受响应的这个通知(notifacation),所以你是不能输入字给他接受的。
所以self.window makeKeyAndVisible他做了几件事情?两件事情对吧。

接下来我们还会看到UIWindow中还有一大堆全局NSString常量,这些都是我们经常用到的通知。好,我们再回到UIView中,现在我们捋一捋,一个app只能有一个Window,而在这个window上面可以放任何view!也可以通过实例方法setRootViewController:xxxController来在window上面加内容。这两种方式区别仅仅是一种是mvc的,一种不是mvc的而已(前者缺少了controller),所以我们现在还没有谈论到controller,暂时先不提这个角色的作用。我们尝试做这样一件事情:
<script src="https://code.csdn.net/snippets/774.js" type="text/javascript"></script>






运行下?hoho,这就是没有Controller的单纯的2个view?nonono,其实controller的意义在于处理逻辑,你说2个view怎么会没有逻辑就被你看到而不混乱呢?那么这里我们的label不再有一个视图控制器(viewController)来控制逻辑,但是model view 任然没有混乱(label上面的text也可以理解为简单的data model....),这个时候我们能不能理解为appDelegate现在充当了控制器的角色呢?是的,其实任何时候appDelegate他比我们的viewController可以实现更多的逻辑

这个时候我们再不仿假设,这个时候我不想让我的这个view直接被appDelegate这种朝廷重臣来管理,这样太麻烦了,他只是一个label而已!!
所以这里我们可以创建一个NSObject子类LableManager,然后给他一个属性,叫做managedLabel,然后在appDelegate中初始化这个Object:


<script src="https://code.csdn.net/snippets/775.js" type="text/javascript"></script>



现在发生了一件非常有趣的事情!!现在manager来充当了view的管理者!!所以现在我们的数据绑定逻辑可以在manager中执行了!
那么我现在实现这个管理者的.m文件:
<script src="https://code.csdn.net/snippets/776.js" type="text/javascript"></script>

?


ok运行看看?
其实到这里,我们相当于没有使用viewController,但是使用了一个自己写的object来充当了viewController的角色而已!除了做数据绑定,你还可以监听你管理的view什么时候准备好让你管理了?(view did load) 什么时候出现在屏幕上了?(view will appear)等等等等
所以视图控制器的角色是什么?他其实就是一个管理者,可以分管一个view,当然也可以分管这个view上的所有的subviews!所以我们的controller中的self.view和我们这里的managedLabel是不是一个概念呢?

好的 下一回我们再细细分析!



610D84CF-81B8-4591-94A7-5F252B7FFF1B.png


69BB3CE0-3DB8-4E56-9EB2-499BAEB39084.png


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics