MENU

iOS实战开发 - ViewController

March 15, 2016 • Read: 985 • Codes

MVC 模式

MVC 模式(Model - View - Controller)是由Trygve Reenskaug于1978年提出,是一种弱耦合思想衍生的架构。

MVC

其中:
Controller 引用Model及View层,但View和Model层不直接引用Controller层,并且他们之间也不互相引用。在iOS开发中,一般情况下,View层通过delegate间接地引用Controller层,而Model层则通过model.observers以发送通知的形式使Controller层响应某些事件。

UIViewController

对应到iOS开发中,Controller层所指代的通常是各种UIViewController。UIViewController在Cocoa Touch 中负责管理View、传递数据、响应用户操作、管理内存、保持状态以及适应设备等。

RootViewController的创建过程

RootViewController 创建过程

首先系统会在我们应用目录下(MainBundle)的Info.plist文件中查找UIMainStoryBoardFile的值,如果找到了,则会在_loadMainInterfaceFile中调用_loadMainStoryboardFileNamed:bundle:使用Storyboard文件初始化主视图。和NSMainNibFile,没找到则会继续查找NSMainNibFile,找到后在_loadMainInterfaceFile中调用_loadMainNibFileNamed:bundle:使用Nib文件初始化主视图。初始化完成后的主视图会自动赋值给当前应用的UIWindow的rootViewController属性。

如果两个都没找到,我们还可以在UIApplicationDelegate类的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;方法中手动创建UIWindow和RootViewController(创建UIViewController后将其赋值给UIWindow的rootViewController属性)。当然,如果我们之前在Info.plist文件中正确设置了UIMainStoryBoardFileNSMainNibFile,这里创建的RootViewController则会将其取代掉。手动创建UIWindow和RootViewController的方法会在后面给出。

那么,如果我们在didFinishLaunching方法中也没创建,那么这个iOS应用就没有UI了,启动后会显示黑屏,并且window也会为nil

手动创建UIWindow

UIApplicationDelegate类(一般为AppDelegate)的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;方法中:

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

View Controller创建其界面的过程

ViewController管理着各种Views,其本身是轻量级的,但其管理的Views确实很重量级的,所以ViewController会尽可能的推迟View的加载,只有必须要访问View时,ViewController才会将其加载(系统也会在必要的时候访问View)。
所以当我们想知道View是否加载时,不能直接去判断一个View是否等于nil,而应该使用ViewController的isViewLoaded方法。

如果一个ViewController方法重写了- (void)loadView;方法,那么系统会使用其初始化View,如果没有,我们可以用手动指定nib的方法创建:

- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil;

当我们使用默认的构造器初始化ViewController时,比如:

UIViewController * myVC = [[MyViewController alloc] init];

在这种情况下,因为ViewController是我们自定义的MyViewController,所以系统会调用+[UIViewController existingNibNameMatchingClassName:bundle:]方法寻找nib文件,如果有MyView.nib,则会使用此nib文件,如果没有,则会判断MyViewController.nib文件是否存在,如果存在则使用其初始化,如果还是不存在,则默认用UIView创建空白视图(黑屏)。
如果我们使用UIViewController的默认初始化方法:

UIViewController *viewController = [[UIViewController alloc] init];

因为是系统定义的类,所以其不会自动查找nib文件,而是默认用UIView创建空白视图。

View Controller的生命周期

View Controller的生命周期

View Controller之间的跳转等

在一个View Controller中显示另一个View Controller时,可以使用:

//Class: UIViewController
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion
//iOS 8及以上可以使用:
- (void)showViewController:(UIViewController *)vc sender:(nullable id)sender;

例如:

if ( ! self.svc ) {
    self.svc = [[SecondViewController alloc] init];
}
self.svc.modalPresentationStyle = UIModalPresentationFullScreen;
self.svc.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:self.svc animated:YES completion:nil];
//或:
//[self showViewController:self.svc sender:self];

关闭一个View Controller时可以调用其dismissViewControllerAnimated: completion:方法:

[self dismissViewControllerAnimated:YES completion:nil];
PresentationStyle
  • UIModalPresentationFullScreen
  • UIModalPresentationFormSheet
  • UIModalPresentationPageSheet
  • UIModalPresentationPopover
  • UIModalPresentationCurrentContext
  • UIModalPresentationNone
  • UIModalPresentationCustom
  • UIModalPresentationOverFullScreen
  • UIModalPresentationOverCurrentContext
TransitionStyle
  • UIModalTransitionStyleCoverVertical
  • UIModalTransitionStyleCrossDissolve
  • UIModalTransitionStyleFlipHorizontal
  • UIModalTransitionStylePartialCurl
数据回传

数据回传可以使用代理的形式:

  • 在主ViewController中定义协议并实现该协议

    //MainViewController.h
    @protocol MainViewControllerDelegate <NSObject>
    
    - (void)completeWithData:(NSArray *)data;
    //...
    
    @end
    
    @interface MainViewController : UIViewController<MainViewControllerDelegate>
    //code
    @end
    
    //MainViewController.m
    //
    - (void)completeWithData:(NSArray *)data {
        //code
    }
  • 在需要回传数据的ViewController中定义协议delegate

    //PresentedViewController.h
    @interface PresentedViewController : UIViewController
    
    @property (weak, nonatomic) id<MainViewControllerDelegate> delegate;
    
    @end
  • 在Present View Controller时将self赋值给需要回传数据的ViewController的delegate属性:

    //In MainViewController.m
    if ( ! self.svc ) {
        self.svc = [[PresentedViewController alloc] init];
    }
    self.svc.modalPresentationStyle = UIModalPresentationFullScreen;
    self.svc.delegate = self; //赋值给需要回传数据的ViewController的delegate
    self.svc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    [self presentViewController:self.svc animated:YES completion:nil];
  • 在需要回传数据时调用delegate中的方法:

    //In PresentedViewController.m
    [self.delegate completeWithData:data];
Tags: iOS, iOS开发
Archives QR Code Tip
QR Code for this page
Tipping QR Code