Использование делегатов, операций и очередей

Я использую AWS SDK для iOS для загрузки и выгрузки файлов с локального жесткого диска и в хранилище Amazon S3. Я способен выполнить эту работу, но не могу заставить делегата S3 правильно ответить, чтобы предупредить меня о завершении операций или об ошибке.

У меня есть массив файлов, которые я хочу загрузить. Для каждого файла я создаю NSOperation где main рутина состоит в основном из:

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

Здесь делегат (s3Delegate) создается как обычный AmazonServiceRequestDelegate, который должен иметь возможность инициировать ответы по завершении операции. Каждый из моих NSOperations добавлены в мой NSOperationQueue который выполняет операции не одновременно. Если я использую делегата [putObjectRequest setDelegate:s3Delegate] операции не работают. Если я удалю использование делегата, операции будут выполнены правильно, но я не смогу получить никаких ответов на операции, поскольку у меня нет делегата.

Если я уберу использование NSOperationQueue полностью и использовать [putObjectRequest setDelegate:s3Delegate] делегат работает отлично.

У меня вопрос, что я делаю не так с использованием делегата в очереди? Поскольку делегат вполне способен выполнять, не находясь в очереди, это может быть связано с отсутствием выполнения в основном потоке? Я действительно хочу иметь возможность использовать очередь, чтобы ограничить количество не параллельных операций, однако я не могу понять это. Я надеюсь, что кто-то имеет представление о том, что здесь происходит, и любой пример кода будет принята с благодарностью. Спасибо! Ура, Тронд

1 ответ

Решение

Кажется, что aws sdk ведет себя асинхронно после того, как вы установили свой делегат. Таким образом, чтобы ваша асинхронная работа с AWS работала в (асинхронной) NSOperation, вы должны приложить некоторые усилия, чтобы дождаться завершения AWS:

В вашем файле.h NSOperation добавьте логическое значение:

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

и в вашем.m файле ваш основной метод будет выглядеть так:

- (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 ….
}

не забудьте реализовать свои методы делегата

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

Примечание: эта магия может работать для любых вещей, которые работают асинхронно, но должны быть реализованы в NSOperation.

Другие вопросы по тегам