Ошибка: 'архиватор закончил;больше ничего не могу закодировать - PullRequest
0 голосов
/ 02 ноября 2011

Я собираюсь загрузить и закодировать изображение, как показано ниже.

Однако я получаю ошибку - [NSKeyedArchiver encodeObject: forKey:]: архиватор завершен; не могу ничего больше кодировать ». Кто-нибудь может объяснить, почему произошла эта ошибка и как я могу ее исправить?

- (void)encodeWithCoder:(NSCoder *)encoder
{
    dispatch_queue_t downloadQueue = dispatch_queue_create("image downloader", NULL);
        dispatch_async(downloadQueue, ^{
            NSURL *url = [NSURL URLWithString:self.avatar_url];
            NSData *data = [NSData dataWithContentsOfURL:url];
            dispatch_async(dispatch_get_main_queue(), ^{
                self.avatar = [[[UIImage alloc] initWithData:data] autorelease];
                [encoder encodeObject:UIImagePNGRepresentation(self.avatar) forKey:@"avatar"];
            });

        });
}

стек ошибок

2011-11-03 00:08:32.645 onethingaday[6897:207] *** Terminating app due to uncaught exception 'NSInvalidArchiveOperationException', reason: '*** -[NSKeyedArchiver encodeObject:forKey:]: archiver has finished; cannot encode anything more'
*** First throw call stack:
(0x29de052 0x26ddd0a 0x2986a78 0x29869e9 0x16e1d40 0x9fdd 0x1d33445 0x1d354f0 0x2915833 0x2914db4 0x2914ccb 0x2d57879 0x2d5793e 0xd89a9b 0x290d 0x2885 0x1)

1 Ответ

2 голосов
/ 02 ноября 2011

Вы не должны использовать асинхронный метод в -encodeWithCoder:. Причина проста. Функция обычно вызывается так (на нижнем уровне):

NSKeyedArchiver* archiver = [NSKeyedArchiver initForWritingWithMutableData:...];
...
[archiver encodeObject:yourObject forKey:@"key"];  // A
// ^ this calls [yourObject encodeWithCoder:archiver]
...
[archiver finishEncoding];   // B

Ваш -encodeWithCoder: асинхронен с GCD. Поэтому строка A вернется до того, как что-либо произойдет, и затем будет выполнена строка B (все равно ваша запланированная функция не будет вызываться). Это завершает работу архиватора и предотвращает дальнейшее кодирование на нем.

Позже асинхронный метод разрешается запускать, и вы загружаете изображение и конвертируете его в PNG и т. Д. ... и, наконец, сообщаете от encoder до -encodeObject:forKey. Но это уже слишком поздно - архиватор уже давно закончил! Поэтому исключение выдается.

Чтобы избежать этого, не следует вызывать -encodeObject:forKey асинхронно. Коды GCD должны быть помещены вне метода -encodeWithCoder:, т. Е. Изображение должно быть полностью доступно до выполнения архивирования.

...