【iOS】initWithNibName原理

使用IB描述控制器view并用代码加载的时候,内部实现逻辑是怎样的?

我们新建一个控制器,控制器viewIB描述。

场景搭建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// LoginViewController.h
#import <UIKit/UIKit.h>
@interface LoginViewController : UIViewController

@end

// LoginViewController.m
#import "LoginViewController.h"

@interface LoginViewController ()

@end

@implementation LoginViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}

创建View.xib的时候,我们一般选择View模板

示例一(TestView.xib

条件:创建一个名称为TestViewIB,用来描述控制器view

加载:

1
2
3
4
5
6
7
8
9
10
11
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

self.window = [[UIWindow alloc] init];
self.window.backgroundColor = [UIColor whiteColor];

LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:@"TestView" bundle:nil];
self.window.rootViewController = loginVC;

[self.window makeKeyAndVisible];
return YES;
}

效果:

把加载方式修改下:initWithNibName:nil

1
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:nil bundle:nil];

修改后的效果:

示例二(Login.xib

条件:创建一个名称为LoginIB,用来描述控制器view

加载:

1
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:@"Login" bundle:nil];

效果:

把加载方式修改下:initWithNibName:nil

1
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:nil bundle:nil];

修改后的效果:

示例三(LoginView.xib

条件:创建一个名称为LoginViewIB,用来描述控制器view

加载:

1
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:@"LoginView" bundle:nil];

效果:

把加载方式修改下:initWithNibName:nil

1
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:nil bundle:nil];

修改后的效果:

示例四(LoginViewController.xib

条件:创建一个名称为LoginViewControllerIB,用来描述控制器view

加载:

1
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:@"LoginViewController" bundle:nil];

效果:

把加载方式修改下:initWithNibName:nil

1
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:nil bundle:nil];

修改后的效果:

扩展

在此基础上如果使用以下代码创建控制器,会默认加载和控制器同名的IB

1
LoginViewController *loginVC = [[LoginViewController alloc] init];

为什么呢?我们重写LoginViewControllerinitWithNibName:bundle:方法看下。

1
2
3
4
5
6
7
8
@implementation LoginViewController

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
NSLog(@"%@", nibBundleOrNil); // 输出:(null)
return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
}

@end

通过输入我们可以看到,即使用init进行初始化,也会进入到initWithNibName:bundle:方法,只不过传入的nibName是空。

总结

如果initWithNibName:指定了IB名称,则按照指定的名称去查找对应的IB文件。如果是nil,则有两种情况:

  • iOS9之前

    • 优先加载控制器同名且去除ControllerIB文件,再去加载控制器同名的IB
    • 例:优先查找LoginView.xib,当不存在时,再查找LoginViewController.xib,如果最终没有找到,则不使用IB
  • iOS9之后

    • 优先加载控制器同名的IB,再去加载去除ControllerIB文件。
    • 例:优先查找LoginViewController.xib,当不存在时,再查找LoginView.xib,如果最终没有找到,则不使用IB