GLKTextureLoader -textureWithCGImage:options:queue:completionHandler: ошибка malloc

Я использую экземпляр GLKTextureLoader для асинхронной загрузки текстуры:

NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] 
                                                    forKey:GLKTextureLoaderOriginBottomLeft];
GLKTextureLoader *asyncLoader = [[GLKTextureLoader alloc] initWithSharegroup:sharegroup];
[asyncLoader textureWithCGImage:image
                        options:options
                          queue:NULL
              completionHandler:^(GLKTextureInfo *textureInfo, NSError *outError) {
                  if (outError) [ISDebugger logError:outError inMethod:_cmd];
                  GLuint textureName = [textureInfo name];
                  if (completionHandler) completionHandler(textureName);
              }];

При первом запуске этот код работает нормально. Однако во второй раз я получаю предупреждение malloc: *** error for object 0xa0cb3c0: pointer being freed was not allocated в консоли. Обратная трассировка показывает, что ошибка возникает в собственном рабочем потоке GLKTextureLoader:

* thread #16: tid = 0x3003, 0x91a32c91 libsystem_c.dylib`malloc_error_break, stop reason = breakpoint 1.1
    frame #0: 0x91a32c91 libsystem_c.dylib`malloc_error_break
    frame #1: 0x91a32e07 libsystem_c.dylib`free + 358
    frame #2: 0x011f5003 CoreGraphics`image_provider_finalize + 29
    frame #3: 0x01b144b3 CoreFoundation`CFRelease + 291
    frame #4: 0x0118d96c CoreGraphics`CGImageBlockSetRelease + 76
    frame #5: 0x0154646c GLKit`-[GLKTexture dealloc] + 65
    frame #6: 0x02184e3d libobjc.A.dylib`_objc_rootRelease + 47
    frame #7: 0x01549da0 GLKit`+[GLKTextureLoader commonTextureWithCGImage:options:error:lock:eaglContext:] + 277
    frame #8: 0x0154b77e GLKit`__71-[GLKTextureLoader textureWithCGImage:options:queue:completionHandler:]_block_invoke_0 + 140
    frame #9: 0x0232b330 libdispatch.dylib`_dispatch_call_block_and_release + 15
    frame #10: 0x0232c439 libdispatch.dylib`_dispatch_worker_thread2 + 302
    frame #11: 0x919dfb24 libsystem_c.dylib`_pthread_wqthread + 346

Очевидно, кажется, что загрузчик текстур что-то перевыпускает. Что я здесь делаю неправильно?


Обновление:

Изображение, передаваемое в метод, получается примерно таким:

NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *imagePath = [bundlePath stringByAppendingPathComponent:imageFilename];
UIImage *uiImage = [UIImage imageWithContentsOfFile:imagePath];
CGImageRef image = [uiImage CGImage];

Изменение генерации изображения на это предотвратило возникновение ошибки:

UIImage *uiImage = [UIImage imageNamed:imageFilename];
CGImageRef image = [uiImage CGImage];

Так что теперь я полагаю, вопрос в том, почему? Я понимаю, что +imageNamed: включает некоторое поведение кэширования, но почему это должно влиять на этот код?


Обновление 2:

То же самое, когда образ создается с помощью [UIImage imageWithData:imageData] (происходит сбой). Вроде работает только [UIImage imageNamed:imageName]. Есть идеи, почему?


person Stuart    schedule 08.07.2012    source источник
comment
Откуда image?   -  person borrrden    schedule 13.07.2012
comment
@borrrden Я обновил вопрос, добавив некоторые детали. Извините за задержку с ответом.   -  person Stuart    schedule 17.07.2012
comment
В вашем блоке завершения у вас есть следующий код if (completionHandler) completionHandler(textureName);, возможно, опубликуйте исходный код для функции completionHandler(), вызываемой здесь.   -  person idz    schedule 17.07.2012
comment
Загрузчик текстур не достигает своего собственного блока completionHandler до того, как произойдет сбой (т. е. ни один код из строки if (outError) ... никогда не запускается), поэтому я не думаю, что это может быть связано. Код в блоке my completionHandler варьируется от случая к случаю, но в основном включает привязку и отрисовку текстуры к FBO (но, как я уже сказал, он никогда не запускается).   -  person Stuart    schedule 17.07.2012


Ответы (1)


вы используете асинхронный метод для обработки этого элемента. скорее всего, это не asyncLoader, который выполняет выпуск, а что-то еще.

если вы объявили изображение как UIImage локально, вызвали этот asyncLoader для запуска, а затем немедленно вышли из текущего stackFrame (т. е. текущего метода, который выполняет этот вызов), переданный вами UIImage, вероятно, будет выпущен до того, как вы что-то сделаете с ним в асинхронный загрузчик. (то же самое произойдет, если UIImage был передан, но выпущен в вызывающем стеке-фрейме... или если он слаб, и вещь, которая содержит ссылку на него, удаляет его до запуска asyncLoader).

я бы предложил сделать сильное @property из изображения (и установить его равным нулю в viewDidUnload вашего viewController), и тогда эта проблема должна исчезнуть.

person john.k.doe    schedule 16.07.2012
comment
Меня бы удивило, если бы экземпляр GLKTextureLoader не фиксировал строго ссылку на передаваемое изображение. Возможно, важно отметить, что вы не передаете UIImage в метод, но CGImageRef... является ссылкой на это все еще зависите от UIImage околачивающегося поблизости? Я обновлю свой вопрос, добавив немного больше подробностей об источнике изображения, но просто скажу здесь, что я думаю, что вы правы в отношении ошибки, связанной с владением ссылкой на изображение. - person Stuart; 17.07.2012