我想下载压缩文件并将其解压缩。当我下载zip时,一切正常。但是,解压缩后,我的界面会停止几秒钟,有时应用程序会崩溃。如何解决?
压缩文件大小650 MB
downloadButton-单击按钮时激活下载
-(IBAction) downloadButton:(id)sender{
_url1 =[NSURL URLWithString:@"link"];
_downloadTask1 = [_session downloadTaskWithURL:_url1];
[_downloadTask1 resume];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
if (downloadTask == _downloadTask1) {
_paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
_documentsDirectory1 = [_paths1 objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *newLocation = [NSURL URLWithString:[NSString stringWithFormat:@"file://%@/1.zip", _documentsDirectory1]];
NSError *error;
[fileManager copyItemAtURL:location toURL:newLocation error:&error];
}
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;{
if( downloadTask == _downloadTask1){
_progress1 = [[NSNumber numberWithInteger:totalBytesWritten] floatValue];_total1 = [[NSNumber numberWithInteger:totalBytesExpectedToWrite] floatValue];
_percentage = [NSString stringWithFormat:@"%.f%%", ((_progress1 / _total1) * 100)];
(NSLog (_percentage, @"%.f%%"));
_label.text = _percentage;
}
if ([_percentage isEqual: @"100%"]) {
_label.text = @«ok»;
[self performSelector:@selector(zip) withObject:nil afterDelay:0.1];
[self performSelector:@selector(removeZip) withObject:nil afterDelay:5.0];
}
}
-(void) zip{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
_documentsDirectory1 = [_paths1 objectAtIndex:0];
_zipPath1 = [_documentsDirectory1 stringByAppendingPathComponent:@"1.zip"];
_destinationPath1 = [NSString stringWithFormat:@"%@",_documentsDirectory1];
[SSZipArchive unzipFileAtPath:_zipPath1 toDestination:_destinationPath1];
});
}
-(void) removeZip{
_paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
_documentsDirectory1 = [_paths1 objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:[_documentsDirectory1 stringByAppendingPathComponent:@"1.zip"] error:nil];
}
您对线程/队列的处理是错误的。
NSOperationQueue
除非您将其专门设置为使用在主线程上运行的队列,否则将在作为后台队列的上调用NSURLSession委托方法。
因此,您可以在委托方法中完成耗时的操作,而不会阻塞UI。
但是,任何更新UI的代码都需要在主线程上执行。
您可以摆脱dispatch_async(dispatch_get_global_queue
解压缩代码周围的包装器,因为除非采取特殊步骤,否则无论如何都会从后台线程调用该代码。
但是,会话委托方法中用于更新标签并进行其他UIKit调用的代码需要在主线程上执行:
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
if (downloadTask == _downloadTask1) {
self.paths1 = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory1 = [_paths1 objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *newLocation = [NSURL URLWithString:
[NSString stringWithFormat: @"file://%@/1.zip",
self.documentsDirectory1]];
NSError *error;
[fileManager copyItemAtURL:location toURL:newLocation error:&error];
[self zip];
[self removeZip];
}
}
- (void)URLSession:(NSURLSession *)session
downloadTask: (NSURLSessionDownloadTask *) downloadTask
didWriteData: (int64_t) bytesWritten
totalBytesWritten: (int64_t) totalBytesWritten
totalBytesExpectedToWrite:(int64_t) totalBytesExpectedToWrite; {
if (downloadTask == _downloadTask1) {
self.progress1 = (float) totalBytesWritten;
self.total1 = (float) totalBytesExpectedToWrite;
self.percentage = [NSString stringWithFormat:@"%.f%%",
((_progress1 / _total1) * 100)];
NSLog(@"%.f%%", self.percentage, );
//Setting a label's text is a UI call so it needs to be done on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
if ([_percentage isEqual: @"100%"]) {
_label.text = @«ok»;
};
else {
_label.text = _percentage;
}
}
}
-(void) zip {
_paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
_documentsDirectory1 = [_paths1 objectAtIndex:0];
_zipPath1 = [_documentsDirectory1 stringByAppendingPathComponent:@"1.zip"];
_destinationPath1 = [NSString stringWithFormat:@"%@",_documentsDirectory1];
[SSZipArchive unzipFileAtPath:_zipPath1 toDestination:_destinationPath1];
}
-(void) removeZip {
_paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
_documentsDirectory1 = [_paths1 objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filename = [_documentsDirectory1 stringByAppendingPathComponent:@"1.zip"];
[fileManager removeItemAtPath: filename error:nil];
}
顺便说一句,这条线是不必要的复杂和低效的:
_progress1 = [[NSNumber numberWithInteger:totalBytesWritten] floatValue];
没有理由创建一个NSNumber
(需要内存分配的对象)。只需将其totalBytesWritten
直接转换为浮点数即可:
self.progress1 = (float) totalBytesWritten;
并且,由于该代码在后台线程上运行,因此您应该使这些属性成为原子属性,并使用语法“ self.property”来使用该属性的getter和setter。
上面的方法中还有其他我未解决的UI调用。我只是以其中之一为例进行了更改。
您处理100%完整的案件也是脆弱和不道德的做法。删除该代码,然后将调用您的(un)zip方法的代码移至完整的下载委托调用中,并删除performSelectorwithObject:afterDelay:
这些调用周围的包装器。
在下载完整的会话委托方法中,移动文件,解压缩并删除它,所有这些都无需调用dispatch_async,因为无论如何该方法都将在后台线程上调用。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句