AmazonS3Client putObject只适用于iOS主线程?

时间:2012-06-04 00:57:11

标签: ios multithreading amazon-s3

我正在尝试使用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。我已经尝试在具有相同失败结果的非主线程上调度函数调用。

5 个答案:

答案 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来检查文件是否存在。