6

我正在尝试使用 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]

在我的代码中(不在主线程中),整个视频上传方法运行(我有一些 NSLogs 来证明这一点),但我从来没有收到任何状态回调,没有抛出异常,并且对象永远不会放入它的存储桶中在 S3 上。

当我像这样在主线程上调用上传函数时:

dispatch_async(dispatch_get_main_queue(), ^(void) {
                    [self uploadVideoToS3];
                });

我收到进度回调,一切正常,对象已成功放入 S3 存储桶。

有谁知道 putObject 是否仅适用于 iOS 主线程?如果是这样,那将是不幸的,因为它通常是 UI 线程。

谢谢,凯文

PS 我尝试在非主线程上分派函数调用,但结果相同。

4

5 回答 5

4

我认为您的线程一旦完成发送请求就会终止,因此回调没有线程可以访问。创建一个线程并不意味着它永远存在。一旦它完成它的任务,它就会结束并被回收到线程池中。要在另一个线程上执行此操作,您将必须设计一个与运行循环集成的方法。Apple docs的Threading Programming Guide中有一个关于它的部分。

于 2012-06-04T01:32:17.850 回答
2

问题实际上是如果您设置委托,S3PutObjectRequest 会异步运行。委托在当前运行循环上发送它的回调,这在主线程上工作正常,但在调度队列线程上却不行。您必须启动自己的运行循环才能处理委托。我仍在尝试确定管理此问题的最佳方法。

当然,我希望他们只提供同步和异步方法,而不是神奇地切换,但这在委托属性的 AmazonServiceRequest.h 头文件中进行了解释。

于 2012-08-10T13:59:40.323 回答
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异步运行。您可以在此处找到有关它的更多信息。

于 2013-04-12T13:59:12.550 回答
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);
}
于 2013-11-25T16:47:43.110 回答
0

感谢您对非主线程 s3 上传的见解。即使上传失败,我也发现了 didCompleteWithResponse 触发器,并且没有找到一种简单的方法来确定它失败了。我正在尝试仅使用 ObjectPut 权限上传,因此程序无法触发 ObjectGet 以检查文件是否存在。

于 2014-04-30T22:02:01.930 回答