项目需求有需要解压,在查了一些资料以后,使用了有关压缩与解压zip文件的第三方“SSZipArchive”, 是用C语言实现的,包装用于OC与swift。
ios系统分为软件包安装目录,和给软件分配的本地缓存目录,解压开始需要获取解压包的路径,解压缩的路径。
app文件所在根目录是:
/data/Containers/Bundle/Application/‘随机key’/appName.app/app本地缓存目录:
/data/Containers/Data/Application/‘随机key’/Documents/
oc获取路径总结:
获取app文件所在根目录:NSString* dir = [NSBundle mainBundle];
获取压缩包路径(第一个参数是文件名,第二个参数是类型):NSString* zipDir = [[NSBundle mainBundle] pathForResource:nameOfZip ofType:@"zip"];
获取文件解压缩路径:
解压缩在模拟器的时候可以解压到app根目录,但是真机上则不行,必须放到app的本地缓存目录。NSString* unzipDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
解压:
解压接口有很多重载,下面找几个容易用到的简短注释说明:
+ (BOOL)unzipFileAtPath:(NSString *)path //压缩包文件路径
toDestination:(NSString *)destination; //解压目录
+ (BOOL)unzipFileAtPath:(NSString *)path //压缩包文件路径
toDestination:(NSString *)destination //解压目录
delegate:(nullable id<SSZipArchiveDelegate>)delegate; //代理
+ (BOOL)unzipFileAtPath:(NSString *)path //压缩包文件路径
toDestination:(NSString *)destination //解压目录
overwrite:(BOOL)overwrite //是否覆盖
password:(nullable NSString *)password //密码(无密码传nil)
error:(NSError * *)error; //解压error
+ (BOOL)unzipFileAtPath:(NSString *)path //压缩包文件路径
toDestination:(NSString *)destination //解压目录
preserveAttributes:(BOOL)preserveAttributes //是否保存属性
overwrite:(BOOL)overwrite //是否覆盖
password:(nullable NSString *)password //密码(无密码传nil)
error:(NSError * *)error //解压error
delegate:(nullable id<SSZipArchiveDelegate>)delegate; //代理
+ (BOOL)unzipFileAtPath:(NSString *)path //压缩包文件路径
toDestination:(NSString *)destination //解压目录
progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler //解压进度回调,参数:文件名,解压信息,当前进度(解压的文件数),总进度(总文件数)
completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler; //解压完成回调,参数:路径,是否成功,错误信息
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
overwrite:(BOOL)overwrite
password:(nullable NSString *)password
progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
异步:
为什么要异步,ios游戏类项目中,如果解压在ui主线程,会占用进程,效果是导致app卡在启动图界面,解压完成后才能继续运行。异步解压,这样用户体验会很好。
如何异步:将解压的过程放在别的线程中,ui主线程等待回调。
具体实现:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//获取app目录路径
NSString* zipDir = [[NSBundle mainBundle] pathForResource:@zipName ofType:@"zip"];
NSString* outputDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
[SSZipArchive unzipFileAtPath:zipDir
toDestination:outputDir
overwrite:YES
password:nil
progressHandler:^(NSString *entry, unz_file_info zipInfo, long entryNumber, long total){
//NSLog(@"解压中 entry:%@", entry);
dispatch_async(dispatch_get_main_queue(), ^{
//调回UI主线程
});
}
completionHandler:^(NSString *path, BOOL succeeded, NSError * _Nullable error){
if (succeeded){
NSLog(@"解压成功 outPut:%@", path);
dispatch_async(dispatch_get_main_queue(), ^{
//调回UI主线程
});
} else {
NSLog(@"解压失败 error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
//调回UI主线程
});
}
}];
});
注意:不要在全局线程里直接调用ui主线程,应用会崩溃。
dispatch_sync(),同步添加操作。他是等待添加进队列里面的操作完成之后再继续执行。
dispatch_async(),异步添加进任务队列,它不会做任何等待。
dispatch_async(dispatch_get_global_queue(0, 0), ^{
});
dispatch_async(dispatch_get_main_queue(), ^{
});