【问题标题】:NSURLSession and stream upload in backgroundNSURLSession 和后台流上传
【发布时间】:2013-11-27 06:54:00
【问题描述】:

我在使用NSURLSession 将照片从资源库上传到服务器时遇到了一些问题。

一开始NSURLSession不支持流式上传。我在尝试使用它时遇到了异常:

@property (nonatomic, strong) NSURLSession *uploadSession;

...

_uploadSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration
                backgroundSessionConfiguration:kUploadBackgroundURLSessionIdentifier] delegate:self delegateQueue:nil];

...

NSURLSessionUploadTask *task = [self.uploadSession uploadTaskWithStreamedRequest:URLRequest];

这是一个例外:

Terminating app due to uncaught exception 'NSGenericException', reason: 'Upload tasks in background sessions must be from a file'

这真的很奇怪,因为 Apple 的手册没有包含有关仅使用 uploadTaskWithRequest:fromFile: 进行后台会话的任何信息。如果我想从资源库上传非常大的视频文件怎么办?我应该先将它保存到我的 tmp 目录吗?

看起来唯一的原因是无论如何都要使用uploadTaskWithRequest:fromFile:,对吧?但是我有一个问题,如果上传过程被中断并开始在后台上传下一部分,服务器如何知道现在正在上传文件的哪一部分?

我应该为此做点什么吗?以前,如果我想继续上传之前启动的部分文件,我会在 URL 请求中使用 Content-Range。现在我不能这样做 - 我必须在创建上传任务之前创建一个 URL 请求,看起来 NSURLSession 必须为我自动执行类似的操作?

有没有人做过类似的事情?谢谢

【问题讨论】:

  • 当我阅读文档时,很明显您必须提供一个背景文件。不确定您的问题 - 如果文件只是部分上传,并且您的服务告诉您收到了多少,那么您可以修剪您的文件并重新发送未发送的部分,不。我没有这样做的经验,但似乎可行。
  • 是的,一切看起来都可行,但有一个问题是,如果我想从资源库上传一个巨大的视频,我必须将它(如果我有足够的空间)复制到我的应用程序文件夹中,然后开始复制,然后不时检查已经上传的内容,修剪文件,并开始新的请求。但是 Apple 的文档告诉我必须为每个文件创建一个任务。
  • 我没有使用资源库的经验 - 您将使用什么框架或类来检索视频?
  • 我为此使用了确切的资产库:) 实际上,来自 ALAssetsLibrary 的任何照片或视频都具有类似资产库:// 的路径,但不可能在 uploadTaskWithRequest:fromFile: 方法中将其用作 URL。所以看起来唯一的解决方案是将它复制到资产库方法assetForURL的结果块中:resultBlock:failureBlock:
  • 您是否尝试将 URL 强制转换为 filePath - NSURL 中有许多有趣的转换。添加另一条评论 - 如果不可能的话我会输入一个应该有的错误。

标签: ios background alassetslibrary uploading nsurlsession


【解决方案1】:

转换成NSData并复制写入app文件夹

ALAsset *asset = [cameraRollUploadImages objectAtIndex:startCount];
ALAssetRepresentation *representation = [asset defaultRepresentation];

// create a buffer to hold the data for the asset's image
uint8_t *buffer = (Byte *)malloc(representation.size);// copy the data from the asset into the buffer
NSUInteger length = [representation getBytes:buffer 
                                  fromOffset:0 
                                      length:representation.size 
                                       error:nil];

// convert the buffer into a NSData object, free the buffer after
NSData *image = [[NSData alloc] initWithBytesNoCopy:buffer 
                                             length:representation.size
                                       freeWhenDone:YES];

【讨论】:

  • 是的,这正是我们正在做的。但是如果用户在 AssetsLibrary 中有一个巨大的视频文件,就会出现问题
【解决方案2】:

目前,只能将图片保存到本地文件系统或临时目录。

以下代码可确保您的数据不会因 exif 标签而丢失。 (ALAsset => NSData)

ALAssetRepresentation *assetRepresentation = [(ALAsset *)assetBeingUploaded defaultRepresentation];
uint8_t *buffer = (uint8_t *)malloc(sizeof(uint8_t)*[assetRepresentation size]);
NSUInteger buffered = 0;
if (buffer != NULL)
buffered = [assetRepresentation getBytes:buffer fromOffset:0.0 length:assetRepresentation.size error:nil];
self.imageBeingUploaded = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];

后台会话中的上传任务不支持完成处理程序。我们应该去。,

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;  

我怀疑如果我们使用后台会话和上传任务以及使用文件的请求,我们如何获取响应标头或正文?

【讨论】:

    【解决方案3】:

    一个干净的解决方法是创建一个 NSOperation,它会使用 NSStream 将文件从资产库复制到您的临时文件夹,这样在操作完成后您就不会在文件很大的情况下崩溃上传该临时文件,上传完成后您将其删除。

    在我的情况下,我需要以多部分格式发送文件,因此需要创建临时文件,但我在上传大文件时遇到问题,超过 2 Gb,例如超过 20 分钟的电影。

    【讨论】:

      【解决方案4】:

      你不能在后台上传 NSData 你需要上传文件格式。可以通过目录路径创建

      【讨论】:

        猜你喜欢
        • 2015-04-04
        • 2014-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多