Using delegates, operations, and queues

I am using the AWS SDK for iOS to upload and download files to and from local hard drive to Amazon S3 storage. I am capable of making this work but I am unable to get the S3 delegate to respond properly to alert me when operations have finished or resulted in an error.

I have an array of files that I want to upload. For each file I create a NSOperation where the main routine consist mostly of:

  • NSURLSession and amazon S3 uploads
  • UIWebView not displaying my webpage
  • Temporary Credentials using AWS IAM
  • Swift 3: Transfer Utility enumerateToAssignBlocks method signature
  • Amazon AWS IOS SDK: How to list ALL file names in a FOLDER
  • IPv6 App Store Rejection
  •     AmazonCredentials * credentials = [[AmazonCredentials alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY];
        putObjectRequest = [[S3PutObjectRequest alloc] initWithKey:pathCopy inBucket:[self bucket]];
        putObjectRequest.filename = pathSource;
        putObjectRequest.credentials=credentials;
        [putObjectRequest setDelegate:s3Delegate];
    

    Here, the delegate (s3Delegate) is created as a regular AmazonServiceRequestDelegate which should be able to fire off responses when an operation has finished. Each of my NSOperations are added to my NSOperationQueue which executes operations non-concurrently. If I use the delegate [putObjectRequest setDelegate:s3Delegate] the operations are not working. If I remove the use of the delegate the operations are performed correctly but I am unable to receive any responses to the operations as I do not have a delegate.

    If I remove the use of the NSOperationQueue completely and use the [putObjectRequest setDelegate:s3Delegate] the delegate works perfectly.

    My question is what am I doing wrong with using a delegate in a queue? Since the delegate is perfectly capable of performing while not in a queue could this be related to not performing on the main thread? I really want to be able to use the queue to limit the number of non-concurrent operations, however I am unable to figure this out. I hope someone has an idea of what is going on here and any example code would be greatly appreciated. Thanks!
    Cheers, Trond

    Solutions Collect From Internet About “Using delegates, operations, and queues”

    It seems that the aws sdk behaves asynchronously after the time you set your delegate.
    So in order to have your asynchronous aws stuff work in a (asynchronous) NSOperation, you got to put some magic to wait for AWS to complete:

    In your .h NSOperation file, add a boolean:

    @interface UploadOperation : NSOperation <AmazonServiceRequestDelegate> {
        @private
        BOOL        _doneUploadingToS3;
    }
    

    and in your .m file, your main method will look like this:

    - (void) main
    {   
        ....  do your stuff …..
    
        _doneUploadingToS3 = NO;
    
        S3PutObjectRequest *por = nil;
        AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY withSecretKey:SECRET_KEY];
        s3Client.endpoint = endpoint;
    
        @try {
            por = [[[S3PutObjectRequest alloc] initWithKey:KEY inBucket:BUCKET] autorelease];
            por.delegate = self;
            por.contentType = @"image/jpeg";
            por.data = _imageData;
    
            [s3Client putObject:por];
        }
        @catch (AmazonClientException *exception) {
            _doneUploadingToS3 = YES;
        }
    
        do {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        } while (!_doneUploadingToS3);
    
        por.delegate = nil;
    
        ....  continue with your stuff ….
    }
    

    do not forget to implement your delegate methods

    -(void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response
    {
        _doneUploadingToS3 = YES;
    }
    
    -(void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error 
    {
        _doneUploadingToS3 = YES;
    }
    
    -(void)request:(AmazonServiceRequest *)request didFailWithServiceException:(NSException *)exception 
    {
        _doneUploadingToS3 = YES;
    }
    
    - (void) request:(AmazonServiceRequest *)request didSendData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
    {
        // Do what you want
    }
    
    -(void)request:(AmazonServiceRequest *)request didReceiveResponse:(NSURLResponse *)response
    {
        // Do what you want
    }
    
    -(void)request:(AmazonServiceRequest *)request didReceiveData:(NSData *)data
    {
        // Do what you want
    }
    

    Note: this magic can work for any stuff that performs asynchronously but have to be implemented in a NSOperation.