控制器和应用数据存储
1、UINavigationController, 继承UIViewController,UINavigationController以栈的形式保存子控制器
1)把控制器添加到导航控制器栈里有两种方式:
导航控制器 UINavigationController *nav = [[UINavigationController alloc] init];
比如有一个控制器:UIViewController *control = [[UIViewController alloc] init];
第一种方式:[nav addChildViewController:control];
第二种方式:[nav pushViewController:control animated:YES];
2)从导航控制器栈里中移出栈顶的控制器:- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
回到指定的子控制器:- (NSArray *)popToViewController:(UIViewController *)viewController ainimated:(BOOL)animated;
回到根控制器:- (NSArray *)popToRootViewController ainimated:(BOOL)animated;
3)UINavigationItem的属性:

//左上角的返回按钮 @property(nonatomic, retain) UIBarButtonItem *backBarButtonItem; //中间的标题视图 @property(nonatomic, retain) UIView *titleView; //中间的标题文字 @property(nonatomic, copy) NSString *title; //左上角的视图 @property(nonatomic, retain) UIBarButtonItem *leftBarButtonItem; //右上角的视图 @property(nonatomic, retain) UIBarButtonItem *rightButtonItem;
2、UIStoryboardSegue : 每个Segue有三个属性:

//唯一标识 @property(nonatomic, readonly) NSString *identifier; //来源控制器 @property(nonatomic, readonly) id sourceViewController; //目标控制器 @property(nonatomic, readonly) id destinationViewController;
执行segue的时候,跳转之前会调用一个方法:- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
一般可以在这个方法做一些准备操作,例如给下一个控制器传值
3、ios应用常用的数据的存储方式主要有:
1)、plist (利用xml属性列表归档NSDictionary、NSArray、NSData、NSNumber等系统类型数据)
2)、NSUserDefaults 偏好设置
3)、NSKeydeArchiver归档(一般用来存储自定义对象)
4)、SQLite(关系型数据库,不能直接存储对象,使用sql语句序列化对象存储)
5)、Core Data (对象型数据库,吧内部环境屏蔽)
4、应用程序沙盒(模拟器沙盒大概路径:/Users/tan/Library/Developer/CoreSimulator/Devices/......)
每个应用程序都有自己的应用沙盒,用来和其他程序隔离;
沙盒的文件系统目录有三个:Documents、Library(又包含Caches和Preferences)、tmp;
1)、应用程序包包含了所有的资源文件和可执行文件;
2)、Documents保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录;
3)、tmp保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时,不会备份该目录;
4)、Library/Caches 保存应用运行时生成的非重要的需要持久化的数据,iTunes同步设备时不会备份该目录;
5)、Library/Prefences保存应用的所有偏好设置,iTunes同步设备时会备份该目录
测试获取应用程序沙盒下和真机下Documents路径和安装包资源文件路径方法:
//沙盒Documents路径 : NSSearchPathForDirectoriesInDomains函数第三个参数布尔类型expandTilde表示是否显示全路径 NSString *path1 = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; NSString *path2 = [NSHomeDirectoryForUser(nil) stringByAppendingPathComponent:@"Documents"]; NSString *path3 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path4 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO) lastObject]; NSLog(@"path1 = %@", path1); NSLog(@"path2 = %@", path2); NSLog(@"path3 = %@", path3); NSLog(@"path4 = %@", path4); //安装包资源文件路径 NSString *indexUrl = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; NSLog(@"indexUrl: %@", indexUrl); /* 模拟器测试打印日志: path1 = /Users/PX/Library/Developer/CoreSimulator/Devices/57E9C8A1-2AB2-48C9-9304-254BF841DC2D/data/Containers/Data/Application/948A9B33-FEB7-479B-90FB-F27D573663DF/Documents path2 = /Users/PX/Library/Developer/CoreSimulator/Devices/57E9C8A1-2AB2-48C9-9304-254BF841DC2D/data/Containers/Data/Application/948A9B33-FEB7-479B-90FB-F27D573663DF/Documents path3 = /Users/PX/Library/Developer/CoreSimulator/Devices/57E9C8A1-2AB2-48C9-9304-254BF841DC2D/data/Containers/Data/Application/948A9B33-FEB7-479B-90FB-F27D573663DF/Documents path4 = ~/Documents indexUrl: /Users/PX/Library/Developer/CoreSimulator/Devices/57E9C8A1-2AB2-48C9-9304-254BF841DC2D/data/Containers/Bundle/Application/67C8E4C2-3DF1-4673-8FE9-48397EDA7759/tan_IOSFuXi.app/index.html 真机测试打印日志: path1 = /var/mobile/Containers/Data/Application/CC29D2BC-F10B-41F4-A1CD-239E379604F6/Documents path2 = /var/mobile/Containers/Data/Application/CC29D2BC-F10B-41F4-A1CD-239E379604F6/Documents path3 = /var/mobile/Containers/Data/Application/CC29D2BC-F10B-41F4-A1CD-239E379604F6/Documents path4 = ~/Documents indexUrl: /var/mobile/Containers/Bundle/Application/2B0645D3-0B3F-46BF-841C-202B5A5A0C4B/tan_IOSFuXi.app/index.html */
5、应用程序数据存储方式示例代码:

//定义两个属性 @property (weak, nonatomic) IBOutlet UITextField *txtPlist; //输入信息 @property (weak, nonatomic) IBOutlet UILabel *lblPlist; //展示信息
1)、使用plist文件来存储系统类数据

//将字典数据存入*.plist文件中 - (IBAction)savePlist:(id)sender{ //沙盒Documents文件夹路径 最后那个参数expandTilde代表是否展开完整路径 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"tan.plist"]; NSDictionary *dic = @{@"msg": self.txtPlist.text}; //原子的写入文件中 if ([dic writeToFile:path atomically:YES]){ self.txtPlist.text = @"保存成功"; } else{ self.txtPlist.text = @"保存失败"; } } //* 读取数据plist文件数据 */ - (IBAction)readPlist:(id)sender{ NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"tan.plist"]; NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path]; self.lblPlist.text = [NSString stringWithFormat:@"%@: %@", [[dic allKeys] firstObject], [[dic allValues] lastObject]]; }
2)、使用偏好设置存储

/* 保存数据到用户偏好设置中 */ - (IBAction)saveDataToUserPreference:(id)sender{ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; // 自动帮我们生成一个plist文件存放在偏好设置的文件夹 [ud setObject:self.txtPlist.text forKey:@"msg"]; // 同步:把内存中的数据和沙盒同步 [ud synchronize]; self.txtPlist.text = @"存储到偏好设置OK"; } /* 从用户偏好设置中读取数据 */ - (IBAction)readDataByUserPreference:(id)sender{ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; self.lblPlist.text = [ud objectForKey:@"msg"]; }
3)、使用NSKeyedArchiver对自定义对象进行归档, 使用NSKeyedUnarchiver解析归档对象
首先自定义类需要实现NSCoding协议,然后实现方法
- (void)encodeWithCoder:(NSCoder *)aCoder; //定义自定义类哪些属性需要归档,如何归档
- (id)initWithCoder:(NSCoder *)aDecoder; // 定义归档对象解析时哪些属性需要解析,如何解析
如果父类也遵守了NSCoding协议,应该在encodeWithCoder:方法中加上一句:[super encodeWithCode:encode];
确保继承的实例变量也能被编码,即也能被归档
确保继承的实例变量也能被解码,即也能被恢复

#import <Foundation/Foundation.h> @interface TanPerson : NSObject <NSCoding> @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) int age; @property (nonatomic, copy) NSString *email; @property (nonatomic, copy) NSString *address; + (instancetype)tanPersonWithDict:(NSDictionary *)dict; - (instancetype)initWithDict:(NSDictionary *)dict; @end

#import "TanPerson.h" @implementation TanPerson + (instancetype)tanPersonWithDict:(NSDictionary *)dict{ return [[self alloc] initWithDict:dict]; } - (instancetype)initWithDict:(NSDictionary *)dict{ if (self = [super init]){ [self setValuesForKeysWithDictionary:dict]; } return self; } /** 对象归档时调用 哪些属性需要归档,又如何归档 */ - (void)encodeWithCoder:(NSCoder *)aCoder{ [aCoder encodeObject:_address forKey:@"tan_address"]; [aCoder encodeInt:_age forKey:@"age"]; [aCoder encodeObject:_name forKey:@"tan_name"]; } /** 解析对象时调用 哪些属性需要解析,如何解析 */ - (id)initWithCoder:(NSCoder *)aDecoder{ if (self = [super init]){ _address = [aDecoder decodeObjectForKey:@"tan_address"]; _age = [aDecoder decodeIntForKey:@"age"]; _name = [aDecoder decodeObjectForKey:@"tan_name"]; } return self; } @end
//控制器内方法

/* NSKeyedArchiver归档 用来存储自定义对象 */ - (IBAction)saveDataToArchiver:(id)sender{ TanPerson *person = [[TanPerson alloc] init]; person.age = 25; person.address = self.txtPlist.text; person.name = @"呼呼"; NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"tanPerson.data"]; if ([NSKeyedArchiver archiveRootObject:person toFile:path]){ self.txtPlist.text = @"对象归档OK了"; } else{ self.txtPlist.text = @"对象归档行动失败!"; } } /* 使用NSKeyedUnarchiver解析归档对象 */ - (IBAction)readyDataByArchiver:(id)sender{ NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"tanPerson.data"]; TanPerson *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; self.lblPlist.text = [NSString stringWithFormat:@"name: %@, age: %d, address: %@", person.name, person.age, person.address]; }
4)使用NSKeyedArchiver归档多个对象和解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /* 使用NSKeyedArchiver归档多个对象 */ - ( IBAction )saveMulObjectByArchive:( id )sender{ TanPerson *person1 = [[TanPerson alloc] init]; person1.name = @ "小毛" ; TanPerson *person2 = [[TanPerson alloc] init]; person2.name = @ "小亲" ; NSString *path = [[ NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES ) lastObject] stringByAppendingPathComponent:@ "tanMulPerson.data" ]; //NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容 NSMutableData *data = [ NSMutableData data]; //新建一块可变数据区 //将数据区连接到一个NSKeyedArchiver对象 NSKeyedArchiver *archiver = [[ NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //开始存档对象,存档的数据都会存储到data中 [archiver encodeObject:person1 forKey:@ "perOne" ]; [archiver encodeObject:person2 forKey:@ "perTwo" ]; //存档完毕 必须调用 [archiver finishEncoding]; //将存档的数据存入文件 [data writeToFile:path atomically: YES ]; self .txtPlist.text = @ "多个对象存档完成了" ; } /* 使用NSKeyedUnArchiver解析多个归档对象 */ - ( IBAction )readMulObjectByArchiver:( id )sender{ NSString *path = [[ NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES ) lastObject] stringByAppendingPathComponent:@ "tanMulPerson.data" ]; //将数据读取到data上 NSMutableData *data = [ NSMutableData dataWithContentsOfFile:path]; //解析数据 NSKeyedUnarchiver *unArchiver = [[ NSKeyedUnarchiver alloc] initForReadingWithData:data]; TanPerson *person1 = [unArchiver decodeObjectForKey:@ "perOne" ]; TanPerson *person2 = [unArchiver decodeObjectForKey:@ "perTwo" ]; [unArchiver finishDecoding]; //恢复完毕 可以不调用 self .lblPlist.text = [ NSString stringWithFormat:@ "name1: %@, name2: %@" , person1.name, person2.name]; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?