项目需求有需要解压,在查了一些资料以后,使用了有关压缩与解压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(), ^{
});