iOS沙盒机制(1)
•iOS应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被称为沙盒 •所有的非代码文件都要保存在此,例如图像、图标、声音、映像、属性列表、文本文件等 –1) 每个应用程序都有自己的存储空间 –2) 应用程序不能翻过自己的围墙去访问别的存储空间中的内容 –3) 应用程序请求的数据都要通过权限检测,假如不符合条件,不会被放行
iOS沙盒结构分析 •应用程序包:(Bundle)包含了所有的资源文件和可执行文件 • •Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录 • •Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积较大、不需要备份的非重要数据 • •Library/Preference:保存应用的所有偏好设置,iOS的设置应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录 • •tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
沙盒目录常用获取方式(1) 获取程序的Home目录 NSString *home = NSHomeDirectory(); 注意: 虚拟机Home目录: /Users/userName/Library/Application Support/iPhone Simulator/6.1/Applications/C926CCFA-A110-45E2-B4AD-7E5679152D99 真机Home目录: /var/mobile/Applications/304D8530-98CB-4043-A208-EBF06E8ADBB9 沙盒目录常用获取方式(2) 获取Documents目录 // 2、获取Documents目录 // NSUserDomainMask 代表从用户文件夹下找 // YES 代表展开路径中的波浪字符“~” NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // 只有一个匹配目录,所以这个集合里面只有一个元素 NSString *doc = documents[0]; // 使用字符串拼接的方式获取目录名 NSString *doc2 = [home stringByAppendingPathComponent:@"Documents"]; 注意: 不建议采用字符串拼接的方式获取目录,因为新版本的操作系统可能会修改默认目录名称。 沙盒目录常用获取方式(3) 获取Cache目录 NSArray *caches = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cache = caches[0]; Preferences目录 通过NSUserDefaults类存取该目录下的设置信息 获取Tmp目录 NSString *tmpDir = NSTemporaryDirectory();
技巧:在Mac显示隐藏文件的方法 显示Mac隐藏文件的命令: defaults write com.apple.finder AppleShowAllFiles -bool true 隐藏Mac隐藏文件的命令: defaults write com.apple.finder AppleShowAllFiles -bool false 注意:需要重启Finder 另外, 在Finder中,按shift+command+g,然后输入: /Users/username/Library/Application Support/iPhone Simulator/6.1/Applications 也可以进入虚拟机应用程序目录,其中username是本机用户名
iOS应用数据存取的常用方式
XML属性列表 —— PList
NSKeyedArchiver 归档
Preference(偏好设置)
SQLite3
Core Data
XML属性列表——PList
属性列表是一种XML格式的文件,扩展名为plist
如果对象是NSArray、NSDictionary类型,可以使用writeToFile:atomically:方法直接写入到属性列表文件
如果对象是NSString、NSData类型,也可以使用writeToFile:atomically:方法写入对应的文件
说明:atomically(写入原子性)
YES:先创建一个临时文件,直到内容完成后再导入目标文件
NO:直接写入文件
注意:如果所指定保存文件的路径不存在,写入文件方法不会报错,文件也不会被保存!
属性列表的局限性
只有支持的数据类型可以被序列化,存储到plist中。无法将其他Cocoa对象存储到plist,不能存储自定义对象
支持的数据类型:
Array
Dictionary
Boolean
Date
Number
String
•将NSArray写入沙盒文件
•将NSDictionary写入沙盒文件
其他格式数据的保存 NSString —— 保存时需要自定字符串编码 UIImage —— 注意UIImage无法写入文件,需要使用NSData数据类型进行中转,NSData可以将任何类型的文件,以二进制格式存储 // 生成图像数据 NSData *data = UIImagePNGRepresentation(image);
Archiver & Unarchiver归档和恢复
特点:
支持复杂的数据对象,包括自定义对象
对自定义对象进行归档处理,对象中的属性需要是基本数据类型,或者是实现了NSCoding协议的对象实例
自定义对象的类也需要实现NSCoding
应用场合
在本地保存自定义对象或数组
保存游戏状态
在网络间传输自定义对象数据
……
Archiver & Unarchiver归档和恢复
特点:
支持复杂的数据对象,包括自定义对象
对自定义对象进行归档处理,对象中的属性需要是基本数据类型,或者是实现了NSCoding协议的对象实例
自定义对象的类也需要实现NSCoding
应用场合
在本地保存自定义对象或数组
保存游戏状态
在网络间传输自定义对象数据
……
NSKeyedArchiver
NSString、NSDictionary、NSArray、NSData、NSNumber等类型的对象,可以直接用NSKeyedArchiver进行归档和恢复
不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
NSCoding协议方法 encodeWithCoder: 每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量 initWithCoder: 每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey:方法解码实例变量 NSCoding协议方法的调用 [NSKeyedArchiver archiveRootObject:toFile:] 会首先调用被归档类对象的encodeWithCoder方法对该对象的属性编码,然后再写入文件进行归档 [NSKeyedUnarchiver unarchiveObjectWithFile:path] 从文件加载数据后,会调用类的initWithCoder方法,实例化该类对象,并恢复属性 NSKeyedArchiver——归档对象的注意 如果父类也遵守了NSCoding协议,需要注意: 在encodeWithCoder:方法中加上一句 [super encodeWithCoder:aCoder]; 确保继承的实例变量也能被编码,即也能被归档 在initWithCoder:方法中加上一句 self = [super initWithCoder:aDecoder]; 确保继承的实例变量也能被解码,即也能被恢复
偏好设置——写入 很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能 每个应用都有个NSUserDefaults实例,通过它来存取偏好设置 例如:保存用户名、字体大小、是否自动登录 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:@"itcast.cn" forKey:@"userName"]; [defaults setFloat:18.0f forKey:@"fontSize"]; [defaults setBool:YES forKey:@"autoLogin"];
偏好设置——读取 // 读取系统偏好 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *userName = [defaults objectForKey:@"userName"]; float fontSize = [defaults floatForKey:@"fontSize"]; BOOL autoLogin = [defaults floatForKey:@"autoLogin"]; 注意:UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘,应用程序就终止了。 出现以上问题,可以通过调用synchornize方法强制写入: [defaults synchronize];