NSURLSession 后台会话中的 NSURLSessionDownloadTask 给出错误

Deb*_*rty 5 objective-c ios nsurlsession

我正在学习 NSURLSession 来制作自定义网络类,并偶然发现了一个非常不寻常的错误。

我的目标很简单,一旦完成,我想将 URL 的响应写入文件中。所以我创建了一个下载任务并将其分配给defaultSessionConfiguration。在将委托分配给配置和不将委托分配给配置(在这种情况下完成处理程序工作)的两种情况下都有效。

现在我转移到backgroundSessionConfigurationWithIdentifier。后台会话不支持 blocks ,因此委托调用是强制性的。

每次都以错误告终。错误如下

Printing description of error:
Error Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo={NSErrorFailingURLKey=http://__________________, NSErrorFailingURLStringKey=http://__________________, NSLocalizedDescription=unknown error}
Run Code Online (Sandbox Code Playgroud)

我想我一定是后台配置写错了,所以我通过创建一个演示下载任务来下载图像并将这个任务添加到这个后台会话中来测试它。这次有效

有效的代码如下:

+ (CustomNetwork *)sharedNetworkObject
{
     if(!netWorkObj)
     {
          netWorkObj = [[CustomNetwork alloc] init];

          //[netWorkObj prepareDataSession];

          //[netWorkObj prepareBackgroundSession];
     }
     return netWorkObj;
}
//
+ (NSOperationQueue *)responseQueue
{
     if(!queue)
     {
          queue = [[NSOperationQueue alloc] init];
     }
     return queue;
}

- (void)prepareDataSession
{
     if(!dataSession)
     {
          NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
          configuration.HTTPMaximumConnectionsPerHost = 5; // This means 1 session can hold to 5 connections
          configuration.timeoutIntervalForRequest = CONNECTION_TIME_OUT;
          configuration.timeoutIntervalForResource = CONNECTION_TIME_OUT;
          dataSession = [NSURLSession sessionWithConfiguration:configuration
                                                      delegate:nil //[CustomNetwork sharedNetworkObject]
                                                 delegateQueue:nil];
     }
}

- (void)prepareBackgroundSession
{
     if(!backgroundSession)
     {
          NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"backgroundSession"];
          configuration.HTTPMaximumConnectionsPerHost = 5; // This means 1 session can hold to 5 connections
          configuration.timeoutIntervalForRequest = CONNECTION_TIME_OUT;
          configuration.timeoutIntervalForResource = CONNECTION_TIME_OUT;
          configuration.discretionary = NO;// For optimizing
          backgroundSession = [NSURLSession sessionWithConfiguration:configuration
                                                      delegate:[CustomNetwork sharedNetworkObject]
                                                 delegateQueue:nil];
     }
}

+ (void)demoBackGroundSessionWorks
{
     NSURL * url = [NSURL URLWithString:@"https://www.wallpapereast.com/static/images/wallpaper-photos-42.jpg"];//@"http://www.hdwallpapersinn.com/wp-content/uploads/2012/09/HD-Wallpaper-1920x1080.jpg"];
     //NSURLSessionConfiguration * backgroundConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:@"backgroundtask1"];

     [[CustomNetwork sharedNetworkObject] prepareBackgroundSession];

     NSURLSessionDownloadTask * downloadTask =[backgroundSession downloadTaskWithURL:url];
     [downloadTask resume];

}
Run Code Online (Sandbox Code Playgroud)

给出了失败的代码:

    +(void)createDownloadConnectionWithUrl:(NSString *)aUrl
                                                    operationKey:(NSString *)operationKey
                                                       jsonParam:(NSString *)jsonString
                                                      HTTPMethod:(NSString *)method
                                                  startImmediate:(BOOL)startImmediate
                                                    downloadPath:(NSString *)downloadPath

    {
         if([[aUrl trimmedString] length] && [self isValidMethod:method] && [[downloadPath trimmedString] length])
         {
              CustomURLRequest *dataRequest = [CustomNetwork requestURLWithString:aUrl];
              dataRequest.downloadDestinationPath = downloadPath;

              [self prepareTheDataRequest:&dataRequest
                           WithParameters:&jsonString
                                ForMethod:&method
                          andOpertaionKey:operationKey];


              // Remove any file if present in the path
              if([[NSFileManager defaultManager] fileExistsAtPath:downloadPath])
              {
                   [[NSFileManager defaultManager] removeItemAtPath:downloadPath error:nil];
              }

              // PS : if you are using BackGroundSession, completion block wont work and will give to a NSGenericException. Reason: 'Completion handler blocks are not supported in background sessions. Use a delegate instead.'

              [[CustomNetwork sharedNetworkObject] prepareBackgroundSession];
              NSURLSessionDownloadTask *downloadTask =  [backgroundSession downloadTaskWithRequest:dataRequest];

if(startImmediate)
          {
               [downloadTask resume];
          }
}
Run Code Online (Sandbox Code Playgroud)

prepare 方法向请求添加标头。

如果我使用dataSession而不是backgroundSession,同样失败的代码会起作用

问:同样的请求在 defaultConfiguration 中有效,但在 backgroundSession 中失败。我是不是遗漏了什么,还是与Apple Docs 的“仅支持上传和下载任务(无数据任务) ”有关。

dga*_*ood 0

后台会话不关心他们正在下载什么(文件或任意数据或其他)。您只需使用下载任务或上传任务,而不是数据任务。但你正在这样做。

\n\n

在没有看到其余代码的情况下,我的猜测是它CustomURLRequestNSURLRequest. 不幸的是, \xe2\x80\x94 不支持 的子类NSURLRequest,特别NSURLSession实际直接添加属性的子类。在 iOS 和 OS X 的各个版本中,您会遇到的错误范围从严重到完全崩溃。我什至见过这样的情况:您从一个请求中获取自定义属性值,同时从另一个完全不同的请求中获取 URL 和标头。

\n\n

您应该在 上创建自定义类别,而不是子类化NSURLRequest。在该类别中,创建 getter 和 setter 方法。

\n\n
    \n
  • 用于[NSURLProtocol propertyForKey:inRequest:]您的吸气剂。
  • \n
  • 用于[NSURLProtocol setProperty:forKey:inRequest:]您的设置器。
  • \n
\n\n

重要提示:NSURLRequest使用这些方法存储在内部的所有对象都必须是属性列表可序列化的。如果您需要将自定义类的实例与 关联起来NSURLRequest,您应该将它们存储在单独的 中NSDictionary,并使用任意字典键(例如调用的结果[[NSUUID UUID] UUIDString]),您可以将其安全地存储在NSURLRequest对象中并稍后用于获取自定义类来自外部词典。

\n