前言:面试时被问到是否重写过loadView?为什么要去重写?当时很懵逼,好像知道要这样干但又说不上来,所以去网上找了找资料,总结一下,在被虐中成长.同时,也把自己不是很清楚的一些知识点做一个汇总,为面试做准备.
🔥view和viewcontroller 🔥
首先我们看一下在swift下的view和viewcontroller :
import UIKit
class testView: UIView {
}
import UIKit
class ViewController: UIViewController {
}
UIViewController
顾名思义:视图控制器。应该在MVC
设计模式中扮演控制层的角色。一些初学者在最开始的时候一直不理解为何有了UIView
还要UIViewController
做什么用,不都是向视图中增加view
。
UIViewController
和Uiview
是两个不同的类,本质都是类
;UIViewController
是视图控制器,而UIView
是视图,也就是说,UIViewController
是控制UIView
的。
🌰可以理解为产品经理(UIViewController)和程序员(UIView),程序员是归经理管理的,经理不干实际的活,天天就知道指挥,而程序员就去实现各种功能展示给用户看,同时需要后台给我们数据(model层)
🌰你也可以认为UIViewController就是一个相框
,而UIView就是一个相片
,相框可以随时随地的拿走这个相片而换另外一张相片,或者在这张相片上加一个新的相片。而相片却不能操纵相框的。
这里要注意:
- UIViewController应该只改变UIView的表现,而不应该处理其它事情,更多的操作通过Delegate来进行.
- UIView是一个视图,UIViewController是一个控制器,每一个viewController管理着一个view(这个view上可能有很多东西).
如果你开发的应用界面非常的简单,确实没有必要用控制器控制视图,但是对于视图中复杂的数据显示和数据处理,如果没有这个控制器,这样会使得代码的继承深度大大增加,不利于代码的阅读
UIViewController的基础功能是管理界面中的view,但是一个复杂的应用程序肯定有好多的视图控制器,那么自然如果视图控制要有管理自己的功能就更加强大。
先看API文档:View controllers rarely operate in isolation.If your application uses a navigation or tab bar controller,or if your application presents views modally,then it typically has several view controllers interacting with each other to implement those navigation features
(视图控制器很少单独使用。假如你的应用程序要使用导航或者转换条控制器,或许是你的应用程序要呈现模态的视图,明显的这里有很多的视图控制器相互关联来实现导航的功能)。
所以可以看出,UINavigationController和UITabBarController
是用来控制视图控制器的使用的,同样他们的跟视图也是UIViewController,这里就说明了UIViewController是自己可以控制自己的
。
这也是为何我们使用UINavigationController的时候不允许在把一个NavigationController推入堆栈中,这样极容易形成自己递归
调用自己,造成堆栈溢出
。
🔥nib文件🔥
Nib
文件是一种特殊类型的资源文件,它用于保存iPhone OS或Mac OS X应用程序的用户接口。Nib文件是Interface Builder文档
。通常您会使用Interface Builder设计应用程序的可视部分-例如窗口或视图。有些时候,您可能也用它来配置一些不可视的对象,例如控制器对象(用于管理窗口和视图)。实际上,所有这些操作都是在编辑一份Interface Builder文档
,即在创建一份对象图。保存文件的时候,就是将该对象图进行归档,加载文件的时候,就是将对象图进行解档。
Nib文件—也就是对象图
-可以包含占位对象,这种对象用于指涉存在于文档之外的对象。这些对象虽然不在文档中,但却可能含有文档内对象的引用,或者被文档内的对象引用。文件拥有者就是一种特殊的占位对象。
在程序运行的时候,您可以使用loadNibNamed:owner:
(或者此方法变种)加载Nib文件。在Nib文件中,文件拥有者是个占位对象,它表示您通过owner参数传给此方法的对象。加载Nib文件的时候,所有在Interface Builder
中建立的关联(文件拥有者和其他对象之间的关联)都能够在运行时重新建立起来。
nib文件是一种数据文件
,用于存储可在应用程序需要时使用的一些“冻结”的对象。大多数情况下,应用程序使用nib文件来存储构成用户界面的窗口和视图。当您将nib文件载入应用程序时,nib装载代码会将文件中的内容转化为应用程序可以操作的真正对象。通过这个机制,nib文件省去了用代码创建那些对象的工作。
Interface Builder
是一个可视化的设计环境
,您可以用它来创建nib文件。您可以将标准对象(比如UIKit框架中提供的窗口和视图)和Xcode工程中的定制对象放到nib文件中。在Interface Builder中创建视图层次相当简单,只需要对视图对象进行简单拖拽就可以了。您也可以通过查看器窗口来配置每个对象的属性,以及通过创建对象间的连接来定义它们在运行时的关系。您所做的改变最终都会作为nib文件的一部分存储到磁盘上。
在运行时,当您需要nib文件中包含的对象时,就将nib文件装载到程序中。典型情况下,装载nib文件的时机是当用户界面发生变化和需要在屏幕上显示某些新视图的时候。如果您的应用程序使用视图控制器,则视图控制器会自动处理nib文件的装载过程,当然,您也可以通过类的方法自行装载。
🔥loadView🔥
UIViewController
的view
从哪里来的?为什么我们创建了一个UIViewController
后可以直接调用self.view?
我们并没有去创建view
啊(只考虑纯代码创建情况)
每次访问UIViewController
的view(比如controller.view、self.view)而且view为nil,loadView
方法就会被调用。这个方法父类UIViewController已经实现了所以才有的self.view
重写loadView
,官方不建议我们再调用[super loadView]
; 因为调用[super loadView]意味着又是系统帮你创建了UIViewController的view
,那你还重写干嘛.
- (void)loadView {
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor orangeColor];
NSLog(@"111");
}
- 这个是一个重写的例子,我们可以尝试不去写
self.view = [[UIView alloc] init];
,会发现系统会报错,因为没有self.view
; - 或者我们用
[super loadView]
替换,也能解决报错,这也从侧面证明了[super loadView]
的作用. - 不实现的情况下直接调用
self.view
会造成死循环,因为重写了loadView
后,调用self.view
,会去判断是否有没有view,没有的情况下回调用loadView
创建,然而loadView
里面并没有实现,同时还使用了view
,造成死循环了,最后会导致程序崩溃.
系统loadView实现猜测:
-(UIView *)view{
if (_view == nil) {
[self loadView];
[self viewDidLoad];
}
return _view;
}
🔥为什么要去重写呢?🔥
UIViewController
中创建view
,然后添加一些其他的view
进行展示,这个是我们经常干的事情.这样很臃肿,所以我们经常会通过把 view
移动到不同的文件并添加引用到原来的 ViewController
之中来改善这样的情况,但是你仍然需要用到 本不应该在 ViewController
中的内容 填满 ViewController
,就比如约束代码和其他设置 view 的代码;更不用说我们现在有两个 view 属性(自己创建的myView
和loadView
创建的原生 view)在 ViewController 之中,而这没有任何好处。
臃肿的 ViewController
以及逻辑过多的 ViewController
都非常难以管理和维护。在像 MVVM
这样的架构下,ViewController
应该主要作为自身的 View
以及 ViewModel
之间的路由器 -- 设置并且约束 View
并不是它们的职责,ViewController
只应该起到前后传递信息的路由作用。
在一个大部分代码都是关于自身 View
的视图代码项目中,能够清晰地拆分你的架构中各部分的职责,对于一个便于维护的项目来说非常重要。你要让你真正构建视图部分的代码完全和你的 ViewController
分离 -- 幸运的是有一个简单的方法,就是重写UIViewController
中原生的View
属性。这样做允许你在分离的文件中管理你的多个 View
,同时也仍能保证你的 ViewController
不用去设置任何 View
。
loadView()
是UIViewController
中并不常见的一个方法,但它是 ViewController
的生命周期中非常重要的一部分,因为它承担着最开始加载出view
属性的责任。当使用 Storyboard
的时候,它会加载出 nib
并将其附加给 view
,但当手动初始化ViewController
时,这个方法所做的一切就是创建出一个空的UIView
。你可以重写这个方法并改变它的行为,并且在 ViewController
的 view
上添加任何类型的 view
。
注意:
view
会自动的约束自己到ViewController
的边界,所以并不需要为myView
设置外部约束!这也是为什么上面重写时直接是self.view = [[UIView alloc] init];
并没有去设置frame的原因,其实你设置了也不影响,因为根本没有任何使用.
🔥viewDidUnLoad:(iOS6之后就已废弃)🔥
这个方法最容易误导人,先看API解释:Called when the controller’s view is released from memory(当控制器的视图从内存中释放的时候被调用),
这个方法是被调用相对于viewDidLoad
方法的,在内存警告的情况下,当试图控制器需要释放它的视图和这个视图中相关联的任何对象来释放内存的时候,调用此方法。
这里还有一点要注意的时,当出现内存警告的时候,是调用正在显示的视图控制器的父视图控制器的viewdidUnload
方法,而不是正在显示的视图控制器的viewDidUnload
方法。因为如果调用了正在显示的视图控制器的viewDidUnload
方法,那么用户正在看的界面就会消失,虽然释放了内存但是用户显然没法接受,自然要释放该视图下面看不到的视图控制器中的视图。被释放的视图,下次加载的时候再调用viewDidLoad
的方法,所以ViewDidUnload
的方法是和viewDidload
方法相互对应的。
🔥ASCII编码 / Unicode编码 / UTF-8编码🔥
ASCII编码:
最早只有127个字母被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。
但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。
你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
Unicode编码
因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
UTF-8编码
新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。
所以,本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间。
UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

参考大佬的链接:
https://juejin.im/post/5b68fe5b6fb9a04fd16039c0
https://blog.csdn.net/mengtnt/article/details/6709930
https://blog.csdn.net/henry_sea/article/details/6708553
网友评论