ios - 为什么后台 NSURLConnection 进入后台时出错?
问题描述
当我的应用程序进入后台时出现此错误。
NSURLConnection finished with error - code -1001 Task <09B84034-9F73-4DB6-A685-D891B1B1068A>.<2> finished with error - code: -1001
我正在使用此代码
- (id<XCDYouTubeOperation>) getVideoWithIdentifier:(NSString *)videoIdentifier completionHandler:(void (^)(XCDYouTubeVideo * __nullable video, NSError * __nullable error))completionHandler
{
NSLog(@"Getting Video Identfifier");
if (!completionHandler)
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"The `completionHandler` argument must not be nil." userInfo:nil];
XCDYouTubeVideoOperation *operation = [[XCDYouTubeVideoOperation alloc] initWithVideoIdentifier:videoIdentifier languageIdentifier:self.languageIdentifier];
operation.completionBlock = ^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
if (operation.video || operation.error)
{
NSAssert(!(operation.video && operation.error), @"One of `video` or `error` must be nil.");
completionHandler(operation.video, operation.error);
}
else
{
NSAssert(operation.isCancelled, @"Both `video` and `error` can not be nil if the operation was not canceled.");
}
operation.completionBlock = nil;
#pragma clang diagnostic pop
}];
};
NSLog(@"Operation - %@", operation ) ;
[self.queue addOperation:operation];
return operation;
}`
- (void) startRequestWithURL:(NSURL *)url type:(XCDYouTubeRequestType)requestType
{
if (self.isCancelled)
return;
// Max (age-restricted VEVO) = 2×GetVideoInfo + 1×WatchPage + 1×EmbedPage + 1×JavaScriptPlayer + 1×GetVideoInfo
if (++self.requestCount > 6)
{
// This condition should never happen but the request flow is quite complex so better abort here than go into an infinite loop of requests
[self finishWithError];
return;
}
XCDYouTubeLogDebug(@"Starting request: %@", url);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
[request setValue:self.languageIdentifier forHTTPHeaderField:@"Accept-Language"];
NSLog(@"Request Type - ",requestType);
// NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request];
// [task resume];
self.dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (self.isCancelled)
return;
if (error)
[self handleConnectionError:error];
else
[self handleConnectionSuccessWithData:data response:response requestType:requestType];
}];
[self.dataTask resume];
self.requestType = requestType;
}
#pragma mark - Response Dispatch
- (void) handleConnectionSuccessWithData:(NSData *)data response:(NSURLResponse *)response requestType:(XCDYouTubeRequestType)requestType
{
NSLog(@"XCDDRequestType - ",requestType);
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)response.textEncodingName ?: CFSTR(""));
// Use kCFStringEncodingMacRoman as fallback because it defines characters for every byte value and is ASCII compatible. See https://mikeash.com/pyblog/friday-qa-2010-02-19-character-encodings.html
NSString *responseString = CFBridgingRelease(CFStringCreateWithBytes(kCFAllocatorDefault, data.bytes, (CFIndex)data.length, encoding != kCFStringEncodingInvalidId ? encoding : kCFStringEncodingMacRoman, false)) ?: @"";
NSAssert(responseString.length > 0, @"Failed to decode response from %@ (response.textEncodingName = %@, data.length = %@)", response.URL, response.textEncodingName, @(data.length));
XCDYouTubeLogVerbose(@"Response: %@\n%@", response, responseString);
switch (requestType)
{
case XCDYouTubeRequestTypeGetVideoInfo:
[self handleVideoInfoResponseWithInfo:XCDDictionaryWithQueryString(responseString) response:response];
break;
case XCDYouTubeRequestTypeWatchPage:
[self handleWebPageWithHTMLString:responseString];
break;
case XCDYouTubeRequestTypeEmbedPage:
[self handleEmbedWebPageWithHTMLString:responseString];
break;
case XCDYouTubeRequestTypeJavaScriptPlayer:
[self handleJavaScriptPlayerWithScript:responseString];
break;
}
}
此代码将在后台自动运行,但几分钟后它会停止并给我上述错误。如何解决这个问题?
编辑 1 (Vinay Kiran 方法) #
我将 nsurlsession 配置更改为后台。
- (instancetype) initWithVideoIdentifier:(NSString *)videoIdentifier languageIdentifier:(NSString *)languageIdentifier
{
if (!(self = [super init]))
return nil; // LCOV_EXCL_LINE
_videoIdentifier = videoIdentifier ?: @"";
_languageIdentifier = languageIdentifier ?: @"en";
// _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"YouTubeID"];
_session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
_operationStartSemaphore = dispatch_semaphore_create(0);
NSLog(@"Initialize the Video Identifier");
return self;
}
然后从后台更改完成处理程序,如果我使用处理程序,它将给出此错误
Swift:'后台会话不支持完成处理程序块。改用委托人。
- (void) startRequestWithURL:(NSURL *)url type:(XCDYouTubeRequestType)requestType
{
if (self.isCancelled)
return;
// Max (age-restricted VEVO) = 2×GetVideoInfo + 1×WatchPage + 1×EmbedPage + 1×JavaScriptPlayer + 1×GetVideoInfo
if (++self.requestCount > 6)
{
// This condition should never happen but the request flow is quite complex so better abort here than go into an infinite loop of requests
[self finishWithError];
return;
}
XCDYouTubeLogDebug(@"Starting request: %@", url);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
[request setValue:self.languageIdentifier forHTTPHeaderField:@"Accept-Language"];
NSLog(@"Request Type - ",requestType);
// NEWLY ADDED
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request];
[task resume];
// self.dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
// {
// if (self.isCancelled)
// return;
//
// if (error)
// [self handleConnectionError:error];
// else
// [self handleConnectionSuccessWithData:data response:response requestType:requestType];
// }];
// [self.dataTask resume];
self.requestType = requestType;
}
现在的问题是我最初使用这个
self.dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (self.isCancelled)
return;
if (error)
[self handleConnectionError:error];
else
[self handleConnectionSuccessWithData:data response:response requestType:requestType];
}];
[self.dataTask resume];
其中handleConnectionSuccessWithData 将接收数据、响应和请求类型。现在,如果我使用 backgroundSessionConfigurationWithIdentifier,我不知道在哪里可以获得数据、响应和请求类型。
解决方案
使用后台线程代替主队列
backgroundSessionConfigurationWithIdentifier:
推荐阅读
- python - ModuleNotFoundError:没有名为“neo4j.addressing”的模块和 ModuleNotFoundError:没有名为“neo4j”的模块
- .net - 在 dotnet 中通过 MbnApi 禁用 SIM PIN
- sql - 两个日期之间的月份
- android - 无法在 Retrofit 2.0 中解析 XML 响应
- ios - 数据中的 imageView.image 未显示
- java - Hibernate 不考虑要插入的字段
- r - 使用 R - 需要根据不规则时间序列预测明年的建议
- reactjs - Azure 上的 React + Express:无效的主机标头
- java - 查找数组中的最高索引值
- java - 在不同的 jdk 版本中运行 spring boot 应用程序