笔记
Xmind
PPT
1-控制器管理
- 控制器以及view的多种创建方式
- UINavigationController的简单使用:添加\移除子控制器
- UINavigationBar内容的设置
- 控制器的生命周期方法
- Segue的使用
- 控制器之间数据的传递
- UITabBarController的简单使用
- UITabBarController和UINavigationController的混合使用
- Modal
2-创建控制器
控制器常见的创建方式有以下几种
- 直接创建
MJViewController *mj = [[MJViewController alloc] init];
- 指定xib文件来创建
MJViewController *mj = [[MJViewController alloc] initWithNibName:@"MJViewController" bundle:nil];
- 通过storyboard创建
- 先加载storyboard文件(Test是storyboard的文件名)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Test" bundle:nil];
- 接着初始化storyboard中的控制器(两种方式)
- 初始化“初始控制器”(箭头所指的控制器)
MJViewController *mj = [storyboard instantiateInitialViewController];
- 通过一个标识初始化对应的控制器
MJViewController *mj = [storyboard instantiateViewControllerWithIdentifier:@”mj"];
3-控制器的View
- 控制器view的延迟加载
- 控制器的view是延迟加载的:用到时再加载
- 可以用isViewLoaded方法判断一个UIViewController的view是否已经被加载
- 控制器的view加载完毕就会调用viewDidLoad方法
4-多控制器的管理
- 一个iOS的app很少只由一个控制器组成,除非这个app极其简单
- 当app中有多个控制器的时候,我们就需要对这些控制器进行管理
- 有多个view时,可以用一个大的view去管理1个或者多个小view
- 控制器也是如此,用1个控制器去管理其他多个控制器
- 比如,用一个控制器A去管理3个控制器B、C、D
- 控制器A被称为控制器B、C、D的“父控制器”
- 控制器B、C、D的被称为控制器A的“子控制器”
- 为了便于管理控制器,iOS提供了2个比较特殊的控制器
- UINavigationController
- UITabBarController
5-UINavigationController
UINavigationController的view结构
UINavigationController的简单使用
- UINavigationController的使用步骤
- 初始化UINavigationController
- 设置UIWindow的rootViewController为UINavigationController
-
根据具体情况,通过push方法添加对应个数的子控制器
UINavigationController的子控制器
- UINavigationController以栈的形式保存子控制器
- @property(nonatomic,copy) NSArray *viewControllers;
- @property(nonatomic,readonly) NSArray *childViewControllers;
- 使用push方法能将某个控制器压入栈
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
- 使用pop方法可以移除控制器
- 将栈顶的控制器移除
-(UIViewController *)popViewControllerAnimated:(BOOL)animated;
- 回到指定的子控制器
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
- 回到根控制器(栈底控制器)
-(NSArray *)popToRootViewControllerAnimated:(BOOL)animated;
###如何修改导航栏的内容
- 导航栏的内容由栈顶控制器的navigationItem属性决定
- UINavigationItem有以下属性影响着导航栏的内容
- 左上角的返回按钮
@property(nonatomic,retain) UIBarButtonItem *backBarButtonItem;
- 中间的标题视图
@property(nonatomic,retain) UIView *titleView;
- 中间的标题文字
@property(nonatomic,copy) NSString *title;
- 左上角的视图
@property(nonatomic,retain) UIBarButtonItem *leftBarButtonItem;
UIBarButtonItem *rightBarButtonItem 右上角的视图
@property(nonatomic,retain) UIBarButtonItem *rightBarButtonItem;
##6-Segue
- Storyboard上每一根用来界面跳转的线,都是一个UIStoryboardSegue对象(简称Segue)
![Snip20170213_201.png](http://upload-images.jianshu.io/upload_images/1609505-3118d2cb7d70cd51.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###Segue的属性
- 每一个Segue对象,都有3个属性
- 唯一标识
@property (nonatomic, readonly) NSString *identifier;
- 来源控制器
@property (nonatomic, readonly) id sourceViewController;
- 目标控制器
@property (nonatomic, readonly) id destinationViewController;
![Snip20170213_202.png](http://upload-images.jianshu.io/upload_images/1609505-352866aea0422f63.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###Segue的类型
- 根据Segue的执行(跳转)时刻,Segue可以分为2大类型
- 自动型:点击某个控件后(比如按钮),自动执行Segue,自动完成界面跳转
- 手动型:需要通过写代码手动执行Segue,才能完成界面跳转
###自动型Segue
- 按住Control键,直接从控件拖线到目标控制器
![Snip20170213_203.png](http://upload-images.jianshu.io/upload_images/1609505-249c5a6f9c9c54c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 点击“登录”按钮后,就会自动跳转到右边的控制器
- 如果点击某个控件后,不需要做任何判断,一定要跳转到下一个界面,建议使用“自动型Segue”
###手动型Segue
- 按住Control键,从来源控制器拖线到目标控制器
![Snip20170213_204.png](http://upload-images.jianshu.io/upload_images/1609505-892d8d8d07212308.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 在恰当的时刻,使用perform方法执行对应的Segue
[self performSegueWithIdentifier:@"login2contacts" sender:nil];
// Segue必须由来源控制器来执行,也就是说,这个perform方法必须由来源控制器来调用
- 如果点击某个控件后,需要做一些判断,也就是说:满足一定条件后才跳转到下一个界面,建议使用“手动型Segue”
###performSegueWithIdentifier:sender:方法
- 利用performSegueWithIdentifier:方法可以执行某个Segue,完成界面跳转
- 接下来研究performSegueWithIdentifier:sender:方法的完整执行过程
[self performSegueWithIdentifier:@“login2contacts” sender:nil];
// 这个self是来源控制器
- 根据identifier去storyboard中找到对应的线,新建UIStoryboardSegue对象
- 设置Segue对象的sourceViewController(来源控制器)
- 新建并且设置Segue对象的destinationViewController(目标控制器)
![Snip20170213_205.png](http://upload-images.jianshu.io/upload_images/1609505-e9e451f60894d6ca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 调用sourceViewController的下面方法,做一些跳转前的准备工作并且传入创建好的Segue对象
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
// 这个sender是当初performSegueWithIdentifier:sender:中传入的sender
- 调用Segue对象的- (void)perform;方法开始执行界面跳转操作
- 如果segue的style是push
- 取得sourceViewController所在的UINavigationController
- 调用UINavigationController的push方法将destinationViewController压入栈中,完成跳转
- 如果segue的style是modal
- 调用sourceViewController的presentViewController方法将destinationViewController展示出来
###Sender参数的传递
[self performSegueWithIdentifier:@“login2contacts” sender:@“jack”];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
##7-控制器的数据传递
- 控制器之间的数据传递主要有2种情况:顺传和逆传
- 顺传
- 控制器的跳转方向: A->C
- 数据的传递方向 : A -> C
- 数据的传递方式 : 在A的prepareForSegue:sender:方法中根据segue参数取得destinationViewController, 也就是控制器C, 直接给控制器C传递数据
(要在C的viewDidLoad方法中取得数据,来赋值给界面上的UI控件)
![Snip20170213_206.png](http://upload-images.jianshu.io/upload_images/1609505-54f54004954ecffa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 逆传
- 控制器的跳转方向: A ->C
- 数据的传递方向 : C ->A
- 数据的传递方式 : 让A成为C的代理, 在C中调用A的代理方法,通过代理方法的参数传递数据给A
![Snip20170213_207.png](http://upload-images.jianshu.io/upload_images/1609505-6627469cc74c3cdb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##8-UITabBarController
###UITabBarController的简单使用
- UITabBarController的使用步骤
- 初始化UITabBarController
- 设置UIWindow的rootViewController为UITabBarController
- 根据具体情况,通过addChildViewController方法添加对应个数的子控制器
###UITabBarController的子控制器
- UITabBarController添加控制器的方式有2种
- 添加单个子控制器
- (void)addChildViewController:(UIViewController *)childController;
- 设置子控制器数组
@property(nonatomic,copy) NSArray *viewControllers;
###UITabBarController的view结构
![Snip20170213_208.png](http://upload-images.jianshu.io/upload_images/1609505-4f545988d072bdf8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![Snip20170213_209.png](http://upload-images.jianshu.io/upload_images/1609505-4c426df4a432b08f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###UITabBar
- 如果UITabBarController有N个子控制器,那么UITabBar内部就会有N个UITabBarButton作为子控件
- 如果UITabBarController有4个子控制器,那么UITabBar的结构大致如下图所示
![Snip20170213_210.png](http://upload-images.jianshu.io/upload_images/1609505-715ec44decd224aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###UITabBarButton
![Snip20170213_211.png](http://upload-images.jianshu.io/upload_images/1609505-05c4840455efa8f4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###App主流UI框架结构
![Snip20170213_212.png](http://upload-images.jianshu.io/upload_images/1609505-32a56168578f76c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###Modal
- 除了push之外,还有另外一种控制器的切换方式,那就是Modal
- 任何控制器都能通过Modal的形式展示出来
- Modal的默认效果:新控制器从屏幕的最底部往上钻,直到盖住之前的控制器为止
- 以Modal的形式展示控制器
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion
- 关闭当初Modal出来的控制器
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion;
![Snip20170213_213.png](http://upload-images.jianshu.io/upload_images/1609505-e89d68e15fa388d4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###9-图片
![控制器view加载.png](http://upload-images.jianshu.io/upload_images/1609505-5bafac4a1e751f6f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![内存警告处理.png](http://upload-images.jianshu.io/upload_images/1609505-f989f56d665128f5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![生命周期方法.png](http://upload-images.jianshu.io/upload_images/1609505-ddf7ebcfa8ea0eae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#总结
1.loadView方法作用以及注意点有哪些?
作用:控制器会调用方法去创建控制器的View.
什么时候调用:当第一次使用控制器的View
开发中loadView使用场景:自定义控制器的View.
1.一旦重写了loadView,表示需要自己创建控制器的View.
2.如果控制器的View还没有赋值,就不能调用控制器View的get方法.会造成死循环.因为控制器View的get方法底层会调用loadView方法.
2.KVC底层实现?
setValue:obj forKeyPath:key的底层实现:
1.它会调用这个属性的set方法.
2.如果没有set方法,它会去判断有没有跟key值同名的成员属性.如果有,就直接赋值.icon = obj.
3.如果没有,那么它还会去判断有没有跟key值名相同带有下划线的成员属性,如果有,就直接赋值,_icon = obj.
4.如果都没有, 就直接报错.找不到对应的成员属性.
3.控制器View懒加载是什么意思?
什么时候用到控制器View的时候,才会调用loadView方法创建控制器的View
4.导航控制器管理原则?
1.当调用导航控制器的push方法时, 就会把一个控制器压入到导航控制器的栈中, 那么刚压入栈中的这个导航控制器就在栈的最顶部.
2.它就会把原来导航控制器View当中存放的子控制器View的内容移除,然后把导航控制器栈顶控制器的View添加到导航控制器专门存放子控制器View当中.
3.注意:只是把控制器的View从导航控制器存放子控制器的View当中移除,并没有把控制器从栈中移除.所以上一个控制器还在.
4.当调用pop当方法时, 就会把导航控制器存放子控制器View当中控制器的View移除,并且会把该控制器从栈里面移除.
5.此时该控制器就会被销毁.接着它就会把上一个控制器的View添加到导航控制器专门存放子控制器的View当中.
5.如果设置导航条内容?
设置导航条的内容,由栈顶控制器的NavgationItem决定.
6.事件是怎么样产生与传递的?
1.当发生一个触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中.
2.UIApplication会从事件队列中取出最前面的事件,将事件传递给主窗口
3.主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件
4.触摸事件的传递是从父控件传递到子控件的.
5.如果一个父控件不能接收事件,那么它里面的了子控件也不能够接收事件.
7.一个控件什么情况下不能够接收事件?
1.不接收用户交互时不能够处理事件:userInteractionEnabled = NO
2.当一个控件隐藏的时候不能够接收事件:Hidden = YES的时候
3.当一个控件为透明白时候也不能够接收事件:alpha <= 0.01
8.如果寻找最适合的View?
1.先判断自己是否能够接收触摸事件,如果能再继续往下判断,
2.再判断触摸的当前点在不在自己的身上.
3.如果在自己身上,它会从后往前遍历子控件,遍历出每一个子控件后,重复前面的两个步骤.
4.如果没有符合条件的子控件,那么它自己就是最适合的View.
9.事件传递与响应的完整过程是什么?
1.先将事件对象由上往下传递(由父控件传递给子控件),找到最合适的控件来处理这个事件。
2.调用最合适控件的touches….方法
3.如果调用了[super touches….];就会将事件顺着响应者链条往上传递,传递给上一个响应者
4.接着就会调用上一个响应者的touches….方法
10.如何判断上一个响应者
1.如果当前这个view是控制器的view,那么控制器就是上一个响应者
2.如果当前这个view不是控制器的view,那么父控件就是上一个响应者
11.UIApplication作用?
1.设置应用提醒数字
2.设置连网状态
3.设置状态栏
4.跳转网页
12.应用程序的程动原理
1.执行Main
2.执行UIApplicationMain函数.
3.创建UIApplication对象,并设置UIApplicationMain对象的代理.
4.开启一个主运行循环.保证应用程序不退出.
5.加载info.plist.加载配置文件.判断一下info.plist文件当中有没有Main storyboard file base name,里面有没有指定storyboard文件,
13.如何创建UIWindow?
1.创建窗口
2.创建控制器
3.设置控制器为窗口的根控制器
4.显示窗口
14.push与show的区别(push与show方法只有在有导航控制器下才有效)
1.push这个方法过期了,通过StoryBoard跳转控制器,从一个控制器的界面按住ctrl拖向下一个控制器,运行时可以从当前控制器跳转到下一个控制器。
2.show方法也是一样,功能相同但他是个新方法,在iphone设备上show显示的是一个控制器窗口,但在ipad的上显示的是两个窗口,一个正常窗口一个是详情页窗口。
3.-viewDidLoad方法在view的整个生命周期中只会调用一次,所以在这个方法里面可以加载子控件和加载网络数据请求
4.-viewWillAppear和-viewWillDisAppear方法里面设置view即将显示时和即将消失时需要设置的操作,这两个方法多次调用