Search code examples
iphoneiosamazon-web-servicesamazon-s3amazon-cloudfront

iOS - Amazon S3 Slow Download


I am creating an iOS app that allows users to write lets say a status update and people can comment on it, like it, interact with it in multiple ways, basically the status update has multiple properties that would be stored with it. Imagine an app with a home-screen of more than 50 of these status updates represented into a table view.

Now take your eyes away and focus on a practice/demo app, a developer trying to master the techniques before the big game (thats me!) So essentially, I have started out by setting up an S3 bucket based in Singapore. I live in Singapore, so there is a server nearby and really everything should be fast and smooth. Except, its just not. Its slow, and its starting to make me annoyed.

I know an app that uses S3 that loads high-definition panorama images with comments, likes etc. and it takes a second or a bit more for all this data to load. I am not sure how they actually carry out the process, I know they store the images on S3 but thats all I know. In my starter demo, I simply upload some pieces of text (say 20) then download them and it takes like 15 seconds under my 60 mbps wifi! These pieces of text don't even exceed a sentence each, they are phrases, so I am really kind of confused here.

I have CloudFront setup but isn't it for websites? I have the manage distributions and URL things all setup but how to setup in my code? This is probably my biggest question to nail down for release later in my other app. Even so, I live in Singapore and the bucket is in the Singapore server, so CloudFront for self-testing / practicing wouldn't be mandatory.

I find this extremely confusing, here is some annotated code I have produced, any problems, misconceptions that is leading it to be slow?

- (void)loadObjects {

S3ListObjectsRequest  *listObjectRequest = [[S3ListObjectsRequest alloc] initWithName: @"testbucketquotes.rohanprostudios"];
S3ListObjectsResponse *listObjectResponse = [[AmazonClientManager s3] listObjects:listObjectRequest];
if(listObjectResponse.error != nil)
{
}
else
{
    S3ListObjectsResult *listObjectsResults = listObjectResponse.listObjectsResult;

    if (objects == nil) {
        objects = [[NSMutableArray alloc] initWithCapacity:[listObjectsResults.objectSummaries count]];
    }
    else {
        [objects removeAllObjects];
    }

    // By defrault, listObjects will only return 1000 keys
    // This code will fetch all objects in bucket.
    NSString *lastKey = @"";
    for (S3ObjectSummary *objectSummary in listObjectsResults.objectSummaries) {

        if ([[objectSummary key] rangeOfString: @"UploadedQuote"].location != NSNotFound) {

        [objects addObject:[objectSummary key]];
        lastKey = [objectSummary key];

        }
    }

    while (listObjectsResults.isTruncated) {
        listObjectRequest = [[S3ListObjectsRequest alloc] initWithName: @"testbucketquotes.rohanprostudios"];
        listObjectRequest.marker = lastKey;

        listObjectResponse = [[AmazonClientManager s3] listObjects:listObjectRequest];
        if(listObjectResponse.error != nil)
        {                
            break;
        }

        listObjectsResults = listObjectResponse.listObjectsResult;

        for (S3ObjectSummary *objectSummary in listObjectsResults.objectSummaries) {

            if ([[objectSummary key] rangeOfString: @"UploadedQuote"].location != NSNotFound) {

                [objects addObject:[objectSummary key]];

            }

            lastKey = [objectSummary key];
        }
    }

    if (objects.count) {

        for (int i = 0; i <= objects.count - 1; i++) {

            S3GetObjectRequest *req = [[S3GetObjectRequest alloc] initWithKey:[objects objectAtIndex: i] withBucket: @"testbucketquotes.rohanprostudios"];

            `// asynchronously loads text (adds to operation queue)`
            AsyncQuoteDownloader *quote = [[AsyncQuoteDownloader alloc] initWithRequest:req andViewController: self];

            [operationQueue addOperation: quote]; 
            // in 'AsyncQuoteDownloader' when finished calls a method in this view controller adding the response to an array and reloading a table
        }

    }
  }

});
 }

Anything wrong with my code that is making it lag so much? I would have thought this would take a matter of milliseconds if an imaging service would take 1 second to load HQ images with likes and comments etc takes 1-2 seconds.

Thank you for any help...

Update


Ok, so the iteration of keys doesn't seem to be the problem here but rather the downloading of the objects. Any thoughts? Thanks...


Solution

  • This is the first time I've ever even seen Objective C, so I may be completely wrong here. But... it looks like you're iterating through the keys of the entire bucket. This is going to be really, really slow with any appreciable quantity of keys.

    A better design would be store a lookup table in something like DynamoDB (since you're already using AWS). You'd query there, get an array of matching id's (S3 keys), and then fetch the match objects from S3.