Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AmazonS3Client putObject only works on iOS main thread?

I'm trying to use AmazonS3Client to putObject. The strange thing is, it only seems to work when I run my putObject code on the iOS main thread.

The code is basically like this:

-(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];
}

The bucket exists, I have permissions, etc. If I simply call

[self uploadVideoToS3]

in my code (which is off the main thread), the whole video upload method runs (I have some NSLogs to prove this), but I never get any status callbacks, no exceptions are thrown, and the object is never put into its bucket on S3.

When I call the upload function on the main thread like so:

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

I get progress callbacks, everything works, and the object is successfully put into the S3 bucket.

Does anyone know if putObject only works on the iOS main thread? If so, that would be unfortunate since it's typically the UI thread.

Thanks, Kevin

P.S. I've tried dispatching the function call on a non-main thread with the same failed result.

like image 609
kevlar Avatar asked Jun 04 '12 00:06

kevlar


3 Answers

I am thinking that your thread terminates once it finishes sending the request, therefore the callbacks have no thread to go to. Creating a thread doesn't automatically mean that it just lives forever. Once it finishes its task, it ends and is reclaimed for the thread pool. To do this on another thread, you are going to have to design a method which integrates with a run loop. There is a section on it in the Threading Programming Guide in the Apple docs.

like image 197
borrrden Avatar answered Oct 08 '22 06:10

borrrden


The problem is actually that the S3PutObjectRequest runs asynchronously if you set the delegate. The delegate sends its callbacks on the current run loop, which works fine on the main thread, but not on a dispatch queue thread. You have to start your own run loop in order to process the delegates. I'm still trying to decide the best way to manage this.

Of course, I wish they would simply provide synchronous and asynchronous methods rather than magically switching, but this is explained in the AmazonServiceRequest.h header file on the delegate property.

like image 38
Duane Fields Avatar answered Oct 08 '22 05:10

Duane Fields


AmazonS3Client's putObject method blocks the main thread. Even i was facing the problem. But i found a better solution in S3TransferManager.

Example Code:

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 runs asynchronously. You can find more info on it here.

like image 2
Saravana Vijay Avatar answered Oct 08 '22 06:10

Saravana Vijay