我正在尝试使用AmazonS3Client来放置对象。奇怪的是,它只在我在iOS主线程上运行putObject代码时才起作用。
代码基本上是这样的:
-(void)uploadVideoToS3
{
S3PutObjectRequest * videoPOR = [[S3PutObjectRequest alloc] initWithKey:video.onlineVideoID inBucket:video.onlineVideoBucketName];
videoPOR.contentType = @"video/quicktime";
videoPOR.data = [NSData dataWithContentsOfURL:video.convertedVideoLocalURL];
videoPOR.delegate = self;
// Put the thumbnail and video into the specified s3
AmazonS3Client * s3 = [AmazonClientManager s3];
[s3 putObject:videoPOR];
[videoPOR release];
}
存储桶存在,我有权限等。如果我只是打电话
[self uploadVideoToS3]
在我的代码中(离开主线程),整个视频上传方法运行(我有一些NSLog来证明这一点),但我从来没有得到任何状态回调,没有抛出异常,并且永远不会放置对象进入S3的桶。
当我在主线程上调用上传功能时,如下所示:
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self uploadVideoToS3];
});
我获得进度回调,一切正常,对象成功放入S3存储桶。
有人知道putObject是否仅适用于iOS主线程?如果是这样,那将是不幸的,因为它通常是UI线程。
谢谢, 凯文
P.S。我已经尝试在具有相同失败结果的非主线程上调度函数调用。
答案 0 :(得分:4)
我认为你的线程一旦完成发送请求就会终止,因此回调没有线程可以去。创建一个线程并不意味着它永远存在。完成任务后,它将结束并回收线程池。要在另一个线程上执行此操作,您将不得不设计一个与运行循环集成的方法。 Apple文档中的Threading Programming Guide中有一节介绍。
答案 1 :(得分:2)
问题实际上是,如果设置了委托,S3PutObjectRequest将异步运行。委托在当前运行循环上发送其回调,该循环在主线程上正常工作,但在调度队列线程上没有。您必须启动自己的运行循环才能处理委托。我仍然在试图决定管理它的最佳方法。
当然,我希望他们只提供同步和异步方法,而不是神奇地切换,但这在委托属性的AmazonServiceRequest.h头文件中有解释。
答案 2 :(得分:2)
AmazonS3Client的putObject 方法阻止主线程。即使我正面临着这个问题。但我在 S3TransferManager 中找到了更好的解决方案。
示例代码:
AmazonS3Client * s3 = [AmazonClientManager s3];
S3PutObjectRequest * videoPOR = [[S3PutObjectRequest alloc] initWithKey:video.onlineVideoID inBucket:video.onlineVideoBucketName];
videoPOR.contentType = @"video/quicktime";
videoPOR.data = [NSData dataWithContentsOfURL:video.convertedVideoLocalURL];
S3TransferManager *manager = [S3TransferManager new];
manager.s3 = s3;
[manager upload:videoPOR];
S3TransferManager 以异步方式运行。您可以在其上找到更多信息here。
答案 3 :(得分:1)
我知道这个问题有点陈旧,但我遇到了同样的问题,想要分享我找到的解决方案:https://github.com/0i0/iOS-Amazon-S3-upload-service。
正如人们所提到的,如果你调用从主线程上传你的数据,那么你需要确保你的线程保持活跃。一种方法是使用NSRunLoops。在下面的代码中,我们看到do-while循环将访问当前线程的运行循环,并将持续该线程,直到上传完成。
-(void)uploadFileWithData:(NSData *)data
fileName:(NSString *)fileName
progress:(void (^)(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progressCallback
success:(void (^)(id responseObject))successCallback
failure:(void (^)(NSError *error))failureCallback
{
progress = progressCallback;
success = successCallback;
failure = failureCallback;
_doneUploadingToS3 = NO;
AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithAccessKey:kAWSAccessKeyID withSecretKey:kAWSsecret];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSString *pathToFile = [NSString stringWithFormat:@"%@%@",kAWSPath,fileName];
// Upload image data. Remember to set the content type.
S3PutObjectRequest *por = nil;
por = [[S3PutObjectRequest alloc] initWithKey:pathToFile inBucket:kAWSBucket];
por.cannedACL = [S3CannedACL publicRead];
@try {
por.delegate = self;
por.contentType = @"image/jpeg";
por.data = data;
[s3Client putObject:por];
}
@catch (AmazonClientException *exception) {
_doneUploadingToS3 = YES;
}
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!_doneUploadingToS3);
por.delegate = nil;
});
}
-(void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response
{
_doneUploadingToS3 = YES;
success(response);
}
答案 4 :(得分:0)
感谢您对非主线程s3上传的见解。即使上传失败,我也找不到didCompleteWithResponse触发器,并且找不到确定失败的简单方法。我尝试仅使用ObjectPut权限上传,因此程序无法触发ObjectGet来检查文件是否存在。