1、状态栏
从iOS7开始,系统提供了2种管理状态栏的方式
(1)通过UIViewController
管理(每一个UIViewController
都可以拥有自己不同的状态栏)
(2)通过UIApplication
管理(一个应用程序的状态栏都是由它统一管理)
备注:在不同的场景需要设置的方式不同
(1) View controller-based status bar appearance = NO;
在iOS9之后,只能是在plist文件中,全局设置状态栏,UIApplication的方法已经被弃用
(2) View controller-based status bar appearance = YES;
a> 没有导航栏UINavigationController的ViewController,由ViewController自己管理自己
// 状态栏的样式
- (UIStatusBarStyle)preferredStatusBarStyle;
// 状态栏的可见性
- (BOOL)prefersStatusHidden;
// 状态栏切换时的动画
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation ;
// 可以使用viewController方法更新状态栏设置
[self setNeedsStatusBarAppearanceUpdate];
b> 有UINavigationController的ViewController,
UINavigationController不会将preferredStatusBarStyle这个方法的调用转给它的子视图,而是有导航栏本身进行管理控制
需要通过导航栏navigationBar的barStyle属性修改,
// 状态栏文本颜色设置为白色
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
// 状态栏文本颜色设置为黑市,默认就是黑色
self.navigationController.navigationBar.barStyle = UIBarStyleDefault;
c> 继承UINavigationController,比如LYNavigationController
重写以下的方法,就可以将状态栏修改的权利下放给ViewController
- (UIViewController *)childViewControllerForStatusBarStyle {
return self.topViewController;
}
- (UIViewController *)childViewControllerForStatusBarHidden {
return self.topViewController;
}
ViewController可以继续使用一下方法修改状态栏
// 状态栏的样式
- (UIStatusBarStyle)preferredStatusBarStyle;
// 状态栏的可见性
- (BOOL)prefersStatusHidden;
// 可以使用viewController方法更新状态栏设置
[self setNeedsStatusBarAppearanceUpdate];
2、openURL
(1)iOS 10之前
[[UIApplication sharedApplication] openURL:url];
(2)iOS10之后
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
}]
备注:作用
(1) 打电话
url = @"tel://10086";
(2) 发短信
url = @"sms://10086";
(3) 发邮件
url = @"mailto://123456@qq.com";
(4) 打开网页
url = @"https://www.baidu.com";
(5) 打开其他的app
3、UIApplication 和 delegate
iOS13之后苹果系统为了支持iPadOS的多窗口,推出了SceneDelegate类
###iOS13之前
Appdelegate负责全权处理App生命周期和UI生命周期
// 应用程序启动完毕时调用
- (void)applicationDidFinishLaunching:(UIApplication *)application;
// 应用程序获取焦点
// 焦点:能否与用户进行交互
- (void)applicationDidBecomeActive:(UIApplication *)application;
// 应用程序将要失去焦点时调用
- (void)applicationWillResignActive:(UIApplication *)application;
// 应用程序即将进入后台
- (void)applicationWillEnterForeground:(UIApplication *)application API_AVAILABLE(ios(4.0));
// 应用程序已经进入后台
- (void)applicationDidEnterBackground:(UIApplication *)application API_AVAILABLE(ios(4.0));
// 当应用程序收到内存警告时调用(程序员去清理缓存、图片、视频)
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application;
// 当应用程序退出的时候调用
- (void)applicationWillTerminate:(UIApplication *)application;
### iOS13之后,
Appdelegate负责处理
* 处理App生命周期
* 新的Scene Session 生命周期
SceneDelegate负责处理
*所有UI生命周期


4、应用程序启动流程
1、执行main函数
2、执行UIApplicationMain,创建UIApplication对象,并设置UIApplication它的代理
3、开启了一个事件循环(mainRunloop),主运转循环,保证应用程序不会退出
4、加载info.plist(判断info.list当中有没有main,如果有,加载Main.storyBoard,如果没有就直接执行第五步)
5、应用程序启动完毕(通知代理应用程序启动完毕)
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
5、UIWindow
### iOS13之前
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 1.创建窗口
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
// 2.设置窗口的根控制器
UIViewController *vc = [UIViewController new];
self.window.rootViewController = vc;
// 3.显示窗口
[self.window makeKeyAndVisible];
## iOS9之后,如果添加了多个窗口,控制器它会自动把状态栏给隐藏掉
// 解决办法:把状态栏给应用程序管理
// 将View controller-based status bar appearance 设置成NO
self.window1 = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
// 2.设置窗口的根控制器
UIViewController *mvc = [UIViewController new];
self.window1.rootViewController = mvc;
// 3.显示窗口
[self.window1 makeKeyAndVisible];
## 设置窗口层级
// 级别等级:UIWindowLevelStatusBar > UIWindowLevelAlert > UIWindowLevelNormal
self.window1.windowLevel = UIWindowLevelStatusBar;
## alertView 、 键盘、状态栏其实都是window
return YES;
}
6、 通过storyBoard加载控制器
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
UIWindowScene *windowScene = (UIWindowScene *)scene;
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
self.window.frame = windowScene.coordinateSpace.bounds;
self.window.backgroundColor = [UIColor grayColor];
// 通过storyBoard加载控制器
// 1、创建storyBoard对象(比如加载Main.storyBoard对象)
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// 2、加载storyBoard箭头指向的控制器
UIViewController *vc = [storyBoard instantiateInitialViewController];
// 可以加载storyBoard中指定的控制,通过storyBoardID
UIViewController *other = [storyBoard instantiateViewControllerWithIdentifier:@"otherStoryBoard"];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
}
#备注
如果初始不需要使用Main.storyBoard,或者是说使用自己其他指定的控制器,请将info.plist文件中的以下值设置为空
Main storyboard file base name = 空值
好处:可以避免应用程序启动的时候默认加载一个Main.storyBoard文件创建一个不需要用的控制器,可以节省内存


7、 通过xib加载控制器


8、 loadView
loadView 是 viewController中View的生命周期其中一环
loadView 作用:用来创建控制器的View
什么时候调用:当控制器的View,第一次使用的时候调用
loadView的底层原理:
1、先判断当前控制器是不是从storeBoard加载的控制器,如果是从storyBoard加载的控制器,那么它就会从storyBoard当中加载的控制器的View,设置当前控制器的view
2、当前控制器是不是从xib当中加载的,如果是从xib当中加载的话,把xib当中指定的View,设置为当前控制的view
3、如果也不是从xib加载的,它会创建一个空白的View
// 一旦重写了loadView的方法,就说明要自己定义View
# 使用场景:当前控制器的View一显示时,就 是一张图片,或者UIWebView
# 好处:可以节省内存,少创建一个空白的View
- (void)loadView {
// 特别注意的一定,比如下面的写法会造成死循环
// 原因:
// self.view.bounds是调用了self.view的getter方法,而self.view的getter方法底层写法类似以下
// - (UIView *)view {
// if (_view == nil) {
// [self loadView];
// }
// return _view;
// }
// self.view = [[UIView alloc]initWithFrame:self.view.bounds];
#正确写法
self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];
#如果想self.view是一张图片,写法如下
UIImageView *imgView = [[UIImageView alloc]initWithImage:@"test.jpg"];
self.view = imgView;
}
- (void)viewDidLoad {
[super viewDidLoad];
}

9、 数据可持续
1、plist文件(不能保存自定义对象 )
// 举例:
// 将一组数组保存到Document目录中的data.plist文件
// Document路径
// 第一个参数:搜索的目录
// 第二个参数:搜索的范围
// 第三个参数:是否展开路径(在iOS中使用YES,MAC才使用NO)
NSString * path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [path stringByAppendingPathComponent:@"data.plist"];
NSArray *dataArr = @[@"one",@"two",@"three"];
[dataArr writeToFile:filePath atomically:YES];
// 读取数据
NSArray *readData = [NSArray arrayWithContentsOfFile:filePath];
NSLog(@"%@",readData);
2、 偏好设置(NSUserDefaults)
// NSUserDefaults它保存也是一个plist文件
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 保存值
[defaults setObject:@"test" forKey:@"name"];
[defaults setBool:1 forKey:@"autoLoin"];
// 取出值
BOOL isAutoLogin = [defaults boolForKey:@"autoLoin"];
NSString *name = [defaults objectForKey:@"name"];
// 立即同步写入(否则系统会在某个时间点保存)
[defaults synchronize];
3、归档
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCoding>
@property (nonatomic, copy , readwrite) NSString *name;
@property (nonatomic, assign, readwrite) NSInteger age;
@end
Person.m
#import "Person.h"
@implementation Person
/// 在归档时,告诉系统哪些属性要保存的
/// @param coder coder
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.name forKey:@"name"];
[coder encodeInteger:self.age forKey:@"age"];
}
/// 解档时,告诉系统哪些属性要解析
/// @param coder coeer
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super init]) {
[coder decodeObjectForKey:@"name"];
[coder decodeIntegerForKey:@"age"];
}
return self;
}
========================== 举例 ===========================
// 备注:归档的对象必须执行NSCoding协议
// 将person通过归档方式保存本地
Person *person = [[Person alloc]init];
person.name = @"one";
person.age = 18;
NSString *path = NSTemporaryDirectory();
NSString *filePath = [path stringByAppendingPathComponent:@"person.data"];
// 归档
// iOS12之后开始弃用
[NSKeyedArchiver archiveRootObject:person toFile:filePath];
// iOS11开始沿用
NSData *saveData = [NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:nil];
[saveData writeToFile:filePath atomically:YES];
// 解档
// iOS12之后开始弃用
Person *result = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
// iOS11开始沿用
NSData *resultData = [[NSData alloc]initWithContentsOfFile:filePath];
Person *resultPerson = [NSKeyedUnarchiver unarchivedObjectOfClass:Person.class fromData:resultData error:nil];
@end
网友评论