Jiahonzheng's Blog

iOS 应用程序开发入门

字数统计: 1.5k阅读时长: 6 min
2019/08/29 Share

项目地址:github.com/Jiahonzheng/MOSAD

本篇博客主要讲述 iOS 应用程序开发的基本概念以及 iOS 应用程序的基本运行机制。

UIApplication

UIApplication 是应用程序的实例,每个 APP 都有自己的 UIApplication 对象,并且是单例的。我们可以通过 [UIApplication sharedApplication] 获取这个对象。

AppDelegate.mapplication 函数下,执行以下代码,我们即可验证单个 APP 内的 UIApplication 对象是以单例存在的。

1
2
3
4
5
6
UIApplication *app1 = [UIApplication sharedApplication];
UIApplication *app2 = [UIApplication sharedApplication];
// 当取消下一行的注释,则会抛出'There can only be one UIApplication instance.'异常
// UIApplication *app2 = [[UIApplication alloc] init];
// 日志输出显示 app1 和 app2 是同一地址
NSLog(@"%p %p", app1, app2);

由于每个 APP 都有属于自己的 UIApplication 对象,而这个对象是需要用户自己创建并初始化的,因此我们需要在 main.m 中调用 UIApplicationMain 方法。

1
2
3
4
5
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

PS: autoreleasepool 是对象自动释放池,概念、实现较为复杂,此处不提及(我也不怎么熟悉,嘿嘿)。

启动分析

main 函数是应用程序运行的起点,下面我们对 iOS 应用程序的启动过程进行分析。

UIApplication 部分中,我们知道 UIApplication 对象是需要用户自己创建并初始化的,所以我们在 main 函数中调用了 UIApplicationMain 方法创建应用程序的 UIApplication 对象。

UIApplicationMain 的作用不仅仅如此,它还涉及到了很多重要的程序设置。

1
2
// Creates the application object and the application delegate and sets up the event cycle.
int UIApplicationMain(int argc, char * _Nullable *argv, NSString *principalClassName, NSString *delegateClassName);

从 API 文档中,我们知道 UIApplicationMain 函数除了能创建应用的 UIApplication 对象,还能创建并初始化 AppDelegate 代理对象,建立事件响应机制,它将对以下系统事件进行监听。

系统事件 AppDelegate 钩子函数
程序加载完毕 application: didFinishLaunchingWithOptions
程序失去焦点 applicationWillResignActive
程序进入后台 applicationDidEnterBackground
程序从后台回到前台 applicationWillEnterForeground
程序获取焦点 applicationDidBecomeActive
程序即将退出 applicationWillTerminate

从上面的表格中,我们可以看到在程序加载完毕后,操作系统会调用代理对象中的 application 函数,而在这个函数中,我们通常会设置 UIWindow 和视图控制器(后面将会提及),因此在此函数执行完毕后,视图也就显示在了屏幕上。

UIWindow

UIWindow 在一个 APP 实例中,只会有一个。iOS 程序启动完毕后,创建的第一个视图控件就是 UIWindow ,接着创建 UIViewController ,并将其添加至 UIWindow ,于是 UIViewControllerView 显示在屏幕上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Use the bounding rectangle of the screen to initialize the window.
// It could also written like the following statement.
// _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// Initialize the ViewController instance.
vc = [[ViewController alloc] init];
// Set the Root View of the window.
[self.window setRootViewController:vc];
// Show the view.
[self.window makeKeyAndVisible];
return YES;
}

通常我们在 AppDelegate 中的 application 方法设置 UIWindow 。而在上面对 UIApplication 的分析中,我们知道 main 函数是创建并初始化 UIApplication ,即创建并初始化代理对象,同时开启对系统事件的监听:当程序加载完毕后,系统通过代理对象 AppDelegate 调用 application: didFinishLaunchingWithOptions 方法,而由于我们在 application 方法中设置了 UIWindow ,故程序加载完成后,我们创建的视图就会显示在屏幕上。

UIViewController

UIViewController 是视图控制器,我们可以在其中的 viewDidLoad 函数(一种生命周期函数)中对页面进行设置。

值得注意的是,我们需要设置根视图控制器,这通常是在 AppDelegateapplication 函数中执行下列语句来完成。

1
2
// Set the Root View of the window.
[self.window setRootViewController:vc];

如果我们没有设置根视图控制器,则会抛出 ‘Application windows are expected to have a root view controller at the end of application launch’ 的异常错误。

我们尝试设置这样的主页面:在屏幕的正中央显示 “Hello World” 。

我们将 ViewController.m 中的 viewDidLoad 函数修改为以下的形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"Hello World");

// Set the size of the current view.
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
// Set the background color of the current view.
self.view.backgroundColor = [UIColor whiteColor];
// Show the "Hello World" label.
UILabel *helloWorldLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width - 50,200)];
// Set the alignment of the content.
helloWorldLabel.textAlignment = NSTextAlignmentCenter;
// Align the label on the center of the screen.
helloWorldLabel.center = self.view.center;
// Set the label content.
helloWorldLabel.text = @"Hello World";
// Set the font color of the content.
helloWorldLabel.textColor = [UIColor blackColor];
// This is important! The label must be added to the current view, otherwise, we can't see it.
[self.view addSubview:helloWorldLabel];
}

按下 command + R ,即刻预览本次的程序运行结果,实际结果如下。

日志输出如下:

Info.plist

Info.plist 的主要作用是提供应用在运行期的配置,这些配置非常重要,不能随意删除,其本质为 XML 文件。

下面解释常用字段的含义:

  • Localization native development region:本地化相关数据
  • Executable file :程序安装包的名称
  • Bundle identifier :唯一标识字符串,在发布应用时需要此字段
  • InfoDicitionary version:当前 Info.plist 的版本信息
  • Bundle name :程序安装后在界面显示的名称
  • Bundle version :应用程序版本号,常用于 App Store 的审核
  • Application require iPhone environment :指明当前程序是否只能运行在 iOS 系统上
  • Launch screen interface file base name :此文件中的视图将作为启动过程中的页面
  • Main storyboard file base name :此文件中的视图将作为程序启动完成后的主画面

Xcode 快捷键

  • option + 单击:显示对应的 API 文档说明
  • command + 单击:可进入对应的定义与实现
  • control + 6 :跳转至当前代码文件中的代码行
  • option + command + ‘←/→’:折叠当前代码块
  • control + I :调整代码缩进
  • command + 1 :显示工程导航器
  • command + F :在当前文件中查找
  • command + shift + O :快速打开
  • command + R :运行应用程序
  • command + B:构建应用程序
CATALOG
  1. 1. UIApplication
  2. 2. 启动分析
  3. 3. UIWindow
  4. 4. UIViewController
  5. 5. Info.plist
  6. 6. Xcode 快捷键