iOS开发基础23-iOS开发中的Info.plist、UIApplication及其Delegate、UIWindow详解
在iOS开发中,有一些系统文件和类是我们经常会接触并且必须熟悉的。这些包括Info.plist
、UIApplication
类及其代理,以及UIWindow
。
一、Info.plist常见设置
1. 什么是Info.plist
在每一个iOS项目中,都会有一个名为"工程名-Info.plist"
的文件,这个文件位于Supporting Files
文件夹下。Info.plist
(全称Information Property List)用于对工程进行一些运行时的配置,比如应用程序的标识符、版本号、图标等。这个文件非常重要,不能删除。
- 在旧版本的Xcode中,项目的配置文件名为
"Info.plist"
。 - 请注意,项目中的其他Plist文件不能带有
"Info"
这个字眼,以免被误认为是主配置文件Info.plist
。 InfoPlist.strings
文件与Info.plist
文件有关联,用于本地化。
2. 常见属性(以文本编辑器打开时的键名表示)
属性 | Key | 描述 |
---|---|---|
Localiztion native development region | CFBundleDevelopmentRegion | 本地化相关属性 |
Bundle display name | CFBundleDisplayName | 应用安装后显示的名称,限制在10-12个字符,超出将会被缩写 |
Icon file | CFBundleIconFile | 应用程序图标名称,通常为Icon.png |
Bundle version | CFBundleVersion | 应用程序的版本号,每次发布新版本到App Store时需要递增 |
Main storyboard file base name | NSMainStoryboardFile | 主storyboard文件的名称 |
Bundle identifier | CFBundleIdentifier | 项目的唯一标识,部署到真机时需要 |
3. PCH文件
PCH(Precompiled Header)文件是一个提前编译好的头文件,用于存放一些公用的宏定义和头文件。它会在编译时自动被引入到每个源文件中。在Xcode中可以通过项目的Build Settings
找到Prefix Header
设置来指定PCH文件。
// 在PCH文件中
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
// 自定义Log,适用于Debug模式,发布时不输出
#ifdef DEBUG
#define XMGLog(...) NSLog(__VA_ARGS__)
#else
#define XMGLog(...)
#endif
// 定义一个判断iOS版本的宏
#define iOS8 ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
#endif
二、UIApplication
1. 什么是UIApplication
UIApplication
对象是应用程序的象征,每个iOS应用都有且只有一个UIApplication
实例,可以通过[UIApplication sharedApplication]
获取。应用程序启动后创建的第一个对象就是UIApplication
对象。
UIApplication
对象主要用于进行一些应用级别的操作。
2. 常用属性和方法
常用属性
-
applicationIconBadgeNumber:设置应用程序图标右上角的红色提醒数字。
[UIApplication sharedApplication].applicationIconBadgeNumber = 10;
-
networkActivityIndicatorVisible:设置联网指示器的可见性。
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
用UIApplication
管理状态栏
从iOS 7开始,状态栏的管理提供了两种方式:通过UIViewController
管理和通过UIApplication
管理。
通过UIViewController
管理
-
状态栏的样式
- (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; }
-
状态栏的可见性
- (BOOL)prefersStatusBarHidden { return NO; }
通过UIApplication
管理
如果你想通过UIApplication
来管理状态栏,需要在Info.plist
中进行设置,并实现相关方法。
使用UIApplication
的openURL:方法
openURL:
方法是一个非常强大的功能,可以用来执行多种操作:
// 打电话
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://10086"]];
// 发短信
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms://10086"]];
// 发邮件
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://12345@qq.com"]];
// 打开一个网页
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.baidu.com"]];
3. UIApplication
单例模式
单例模式是指一个类只能存在一个实例。UIApplication
就是通过单例模式实现的。
// 获取应用程序的象征
UIApplication *app = [UIApplication sharedApplication];
下面是模仿苹果内部原理写的一个单例对象:
#import <Foundation/Foundation.h>
@interface Person : NSObject
+ (instancetype)sharedPerson;
@end
#import "Person.h"
@implementation Person
static Person *p = nil;
+ (void)load {
// 应用启动时创建单例实例
[self sharedPerson];
}
+ (instancetype)sharedPerson {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"dispatch_once");
p = [[self alloc] init];
});
return p;
}
+ (instancetype)alloc {
if (p) {
NSException *exce = [NSException exceptionWithName:@"NSInternalInconsistencyException" reason:@"There can only be one Person instance." userInfo:nil];
[exce raise];
}
return [super alloc];
}
@end
三、UIApplication及其Delegate
1. 应用程序的生命周期和系统事件
iOS应用程序会经常受到各种干扰,例如来电、锁屏等。这些系统事件发生时,UIApplication
会通知其代理(delegate)对象,由delegate来处理这些事件。
常见的事件包括:
- 应用程序的生命周期事件(如启动和关闭)
- 系统事件(如来电)
- 内存警告
2. UIApplicationDelegate
协议
UIApplicationDelegate
协议定义了一些用于处理应用程序状态和系统事件的方法,例如:
// 应用接收到内存警告时调用
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application;
// 应用进入后台时调用(比如按了home键)
- (void)applicationDidEnterBackground:(UIApplication *)application;
// 应用启动完毕时调用
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
3. AppDelegate
每次新建项目时,都会自动创建一个带有“AppDelegate”字眼的类,它就是UIApplication
的代理。该类默认已经遵守了UIApplicationDelegate
协议,并实现了相关的生命周期方法。例如:
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 应用启动后的初始化代码
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 应用进入后台时执行的代码
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
// 应用接收到内存警告时执行的代码
}
@end
四、UIWindow
1. 什么是UIWindow
UIWindow
是UIView
的子类,通常在一个应用程序中至少会有一个UIWindow
。应用程序启动时,首先会创建一个UIWindow
,然后再创建视图控制器的view,最后将视图添加到UIWindow
上,使之显示在屏幕上。
2. 添加UIView到UIWindow的方式
可以通过以下两种常见方式将UIView
添加到UIWindow
中:
-
直接将
UIView
添加到UIWindow
中,但不会理会UIView
对应的UIViewController
。[window addSubview:yourView];
-
使用
rootViewController
属性设置根视图控制器,该视图控制器的view会自动添加到UIWindow
中,并管理其生命周期。window.rootViewController = yourViewController;
3. UIWindow常用方法
makeKeyWindow
:将当前UIWindow
变为主窗口(keyWindow)。makeKeyAndVisible
:将当前UIWindow
变为主窗口并显示出来。
4. 获取UIWindow
-
获取应用程序中所有打开的
UIWindow
列表:NSArray *windows = [UIApplication sharedApplication].windows;
-
获取当前应用程序的主窗口:
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
-
获取某个
UIView
所在的UIWindow
:UIWindow *viewWindow = yourView.window;
五、iOS程序的启动过程
应用程序启动时,main
函数调用UIApplicationMain
函数:
int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
参数解释:
argc
和argv
:传递给UIApplicationMain进行相关处理即可。principalClassName
:指定应用程序类名,通常为UIApplication
或其子类;如果为nil
,则用UIApplication
类作为默认值。delegateClassName
:指定应用程序的代理类,该类必须遵守UIApplicationDelegate
协议。
UIApplicationMain
函数会创建UIApplication对象和其delegate,设置run loop进行事件处理。程序启动后会首先调用delegate的application:didFinishLaunchingWithOptions:
方法。
六、四大对象的关系
UIApplication
:代表整个应用程序,是单例模式,负责应用级别的操作。UIApplicationDelegate
:处理应用程序的生命周期事件和系统事件。UIWindow
:是UIView
的子类,显示和管理应用程序的内容。UIViewController
:负责管理视图和处理用户交互。
它们之间的关系可以简单描述为:
UIApplication
通过UIApplicationDelegate
管理应用的生命周期。- 应用启动时,创建
UIWindow
,然后设置rootViewController
,将视图控制器的view添加到UIWindow
上。