【问题标题】:Objective-C: Fading GUIObjective-C:衰落的 GUI
【发布时间】:2016-11-15 23:27:59
【问题描述】:

我想下载压缩包并解压。当我下载 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];
}

【问题讨论】:

  • 如果崩溃,控制台是否有任何错误信息?你必须在主线程上解压缩吗?
  • 1.我检查控制台。没有消息。应用程序只是折叠。 2.如果我不使用dispatch_async app fading。如果我使用 dispatch_async 应用程序滞后

标签: ios objective-c zip


【解决方案1】:

您对线程/队列的处理是错误的。

NSURLSession 委托方法在 NSOperationQueue 上调用,这是一个后台队列,除非您专门将其设置为使用在主线程上运行的队列。

因此,您可以在委托方法中执行耗时的操作,而不会阻塞 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,因为无论如何该方法都会在后台线程上调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-14
    • 2016-10-21
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-13
    相关资源
    最近更新 更多