iOS线程意外退出

时间:2018-08-08 10:24:41

标签: multithreading nsoperation runloop

XXXXOperation是NSOperation的子类,在主函数中,我用AFNetwork实现了文件下载器,有时它在完成块(死代码)处崩溃,崩溃原因是“-[NSURL initFileURLWithPath:] nil字符串参数”。原因是线程在完成执行时退出,但是我不知道为什么?我尝试重现异常,但未成功!有人可以解释吗?谢谢!

@interface XXXXOperation : NSOperation
@property (nonatomic, strong) NSPort *port;
@end

@implementation XXXXOperation

- (void)main
{
@autoreleasepool {
    if (self.pluginInfo.pluginId > 0 && self.pluginInfo.downloadUrl.absoluteString.length > 0)
    {
        self.currentThread = [NSThread currentThread];
        NSString *pluginId = self.pluginInfo.pluginId.length > 0 ? self.pluginInfo.pluginId : @"";
        NSNumber *pluginVersion = @(self.pluginInfo.pluginVersion);

        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
        configuration.timeoutIntervalForRequest = 20;
        AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
        manager.completionQueue = [RNPluginDownloadHelper getCompletionQueue];

        NSMutableSet *acceptableContentTypes = [[NSMutableSet alloc] initWithSet:[(AFHTTPResponseSerializer *)manager.responseSerializer acceptableContentTypes]];
        [acceptableContentTypes addObject:@"application/zip"];

        NSMutableIndexSet *acceptableStatusCodes = [[NSMutableIndexSet alloc] initWithIndexSet:[(AFHTTPResponseSerializer *)manager.responseSerializer acceptableStatusCodes]];
        [acceptableStatusCodes addIndexesInRange:NSMakeRange(300, 200)];

        AFHTTPResponseSerializer *httpRespSerializer = [AFHTTPResponseSerializer serializer];
        httpRespSerializer.acceptableContentTypes = acceptableContentTypes;
        httpRespSerializer.acceptableStatusCodes = acceptableStatusCodes;
        manager.responseSerializer = httpRespSerializer;

        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:self.pluginInfo.downloadUrl];
        request.timeoutInterval = 20;
        self.currentLength = [self fileLengthForPath:[self tempFilePath]];
        NSString *range = [NSString stringWithFormat:@"bytes=%llu-", self.currentLength];
        [request setValue:range forHTTPHeaderField:@"Range"];

        self.tryToUnzipWhen416Occour = NO;

        __weak typeof(self) wself = self;
        NSURLSessionDataTask *downloadTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {

            [wself.fileHandle closeFile];
            wself.fileHandle = nil;

            NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
            if (httpResp.statusCode == 206 && error == nil)
            {
                // this line crash
                *****NSURL *fileURL = [NSURL fileURLWithPath:[wself tempFilePath]];******
                [wself performSelector:@selector(handlePackageZipFileWithFilePath:) onThread:[wself currentThread] withObject:fileURL waitUntilDone:NO];
            }
            else if (wself.tryToUnzipWhen416Occour && httpResp.statusCode == 416 && error.code == NSURLErrorCancelled )
            {
                NSURL *fileURL = [NSURL fileURLWithPath:[wself tempFilePath]];
                [wself performSelector:@selector(handlePackageZipFileWithFilePath:) onThread:[wself currentThread] withObject:fileURL waitUntilDone:NO];
            }
            else
            {           
                [wself performSelector:@selector(finishThread) onThread:[wself currentThread] withObject:nil waitUntilDone:NO];
            }
        }];

        [manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response) {
            NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;

            if (httpResp.statusCode == 206)
            {
                wself.fileLength = response.expectedContentLength + wself.currentLength;

                NSString *filePath = [wself tempFilePath];
                NSFileManager *fileManager = [NSFileManager defaultManager];
                if (![fileManager fileExistsAtPath:filePath])
                {
                    [fileManager createFileAtPath:filePath contents:nil attributes:nil];
                }
                wself.fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];

                return NSURLSessionResponseAllow;
            }
            else if (httpResp.statusCode == 416)
            {
                NSString *contentRange = [[httpResp allHeaderFields] objectForKey:@"content-range"];
                if ([contentRange hasPrefix:@"bytes"])
                {
                    NSRange slashRange = [contentRange rangeOfString:@"/"];
                    if (slashRange.location != NSNotFound)
                    {
                        NSString *strLength = [contentRange substringFromIndex:(slashRange.location + 1)];
                        long long length = strLength.longLongValue;
                        if (length == wself.currentLength)
                        {
                            wself.fileLength = length;

                            wself.tryToUnzipWhen416Occour = YES;

                            return NSURLSessionResponseCancel;
                        }
                    }
                }
            }

            return NSURLSessionResponseAllow;
        }];

        [manager setDataTaskDidReceiveDataBlock:^(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data) {

            [wself.fileHandle seekToEndOfFile];
            [wself.fileHandle writeData:data];

            wself.currentLength += data.length;

        }];

        [downloadTask resume];

        NSRunLoop *runloop = [NSRunLoop currentRunLoop];
        self.port = [NSMachPort port];
        [runloop addPort:self.port forMode:NSDefaultRunLoopMode];
        [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

    }
}
}

- (NSString *)tempFilePath
{
NSString *fileName = [NSString stringWithFormat:@"%@_%@_%@", self.pluginInfo.pluginId, @(self.pluginInfo.pluginVersion), self.pluginInfo.pluginFileMD5];
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];

return filePath;
}

0 个答案:

没有答案