Передача CGImage / UIImage вызывает EXE-BAD-ACCESS - PullRequest
1 голос
/ 09 августа 2011

ИСПРАВЛЕНО: Я пока не уверен, почему.Код был обновлен ниже, а примечания внизу

У меня очень странная ошибка, которая не отображается на симуляторе (даже при работе с инструментами), если я не включаю всех зомбии параметры отладки.Тем не менее, это будет сбой телефона после минуты обновлений (1 обновление в секунду).У меня есть 2D-массив, который я беру подмножество, применяю цветовую карту и превращаю в изображение (этот массив постоянно меняется).Затем я передаю это изображение в модель, и viewcontroller извлекает его из модели, как только получает уведомление об обновлении.Я размечу 3 класса: Спектрограмма, Модель, ViewController:

Вот важные биты каждого (есть больше, но не уместно):

Spectrogram.h (Извините, яздесь невозможно сделать правильный отступ)

@interface: Spectrogram : NSObject
{
    NSMutableData *arrayData;
}
//renamed so Xcode allows the object with +1 reference count to be returned
- (CGImageRef)newSpectrogramImage;  

Spectrogram.m

@implementation Spectrogram
- (CGImageRef)newSpectrogramImage
{
    //slightly reordered
    NSMutableData *imageData = [[NSMutableData alloc] init];
    ...code to go through arrayData and colormap it (get RGB transform) and store in imageData...
    CGImageRef arrayImage = nil;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    //specifically tell CGImage there is no alpha channel
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNone;
    //Use the toll-free bridge between NSData and CFData
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)imageData);
    arrayImage = CGImageCreate((slices-startSlice), bins, 8, 24, 3*(slices-startSlice), colorSpace, bitmapInfo, provider, NULL, false, kCGRenderingIntentDefault);  //image is rotated now, so width and height are switched
    CGColorSpaceRelease(colorSpace);
    CGDataProviderRelease(provider);
    CGImageRelease(arrayImage);
    [imageData release];
    //Pass the CGImageRef with a reference count of 1
    return arrayImage;
}

Model.h

@interface: Model : NSManagedObject
{
    Spectrogram *spectrogram;
}
//Function the viewController can call to get the update
- (CGImageRef)newSpectrogramImage;  

Model.m

@implementation Model
... there is a function that adds new data to the array and notifies all listeners...
- (CGImageRef)newSpectrogramImage {
    return [spectrogram newSpectrogramImage];
}

ViewController.h

@interface: ViewController : UIViewController 
{ 
}
//the root controller actually alloc's the record, and sets this property when creating this view
@property (nonatomic, retain) Record *currentRecord;  

ViewController.m

@implementation ViewController
@synthesize spectrogramView;
- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter ... listen for model updates...
}

//now, the real meat
- (void)recordUpdated:(NSNotification*)notification
{
    CALayer *myLayer = self.view.layer;
    CGImageRef spectrogramImage = nil;
    spectrogramImage = [currentRecord newSpectrogramImage];
    myLayer.contents = (id)spectrogramImage;
    CGImageRelease(spectrogramImage); 
}

Я так много раз менял за последний день, пытаясь найти где и почемувыходит из строя.Вместо этого я попытался передать CGImageRef (но поскольку это не объект, я беспокоюсь о том, чтобы сделать копии того, что может быть огромным образом), и он все равно не работает.И это прекрасно работает в симуляторе (будет работать в течение десятков минут).Но происходит сбой в течение минуты на iphone, или если я включаю параметры отладки для симулятора (он потерпит неудачу, как только загрузится viewcontroller).

На заметку, которая может быть полезна,Этот view-контроллер загружается как модальный вид, когда телефон повернут вбок (прекрасно работает).Тем не менее, у меня есть много NSLogs там, и я вижу, что dealloc этого viewcontroller вызывается еще до того, как mainviewcontroller даже добирается до viewwilldisappear - но он все еще работает.А затем снова вызывается dealloc этого контроллера, когда телефон возвращается и представление исчезает.

Примечание Версия, которая хорошо работала в симуляторе, прошла CGImageRefs вплоть до viewController, вместо этогоUIImages.Я попробовал по крайней мере 50 различных комбинаций того, где создать UIImage из CGImage, и то, что опубликовано выше, является лишь одним из них (все они в конечном итоге терпят неудачу или сразу).Следует отметить, что с помощью приведенного выше кода, если я добавлю это в viewController modelUpdated:

CGSize size = currentModel.spectrogramImage.size;
NSLog(@"width: %f", size.width);

и закомментирую, назначив его для spectrogramView, ширина сообщается правильно, поэтому UIImage передается,он просто не сохраняется (так я понимаю ошибку EXE_BAD_ACCESS).

Кроме того, недавно я получил dan EXE_BAD_ACCESS в строке

self.spectrogramImage = [spectrogram getSpectrogramImage];

.Итак, я думаю, что ошибка может быть внутри класса Spectrogram.Хотя код CGImage и UIImage был взят из примеров Apple.

Исправлены заметки Я читал, что установка содержимого CALayer была гораздо более быстрым способом передачи CGImageRef в представление - инет UIImage посредника.К сожалению, я фиксирую только рабочие изменения, поэтому я не вижу каждую итерацию, которую я прошел.Тем не менее, я знаю, что у меня было что-то очень похожее на это несколько раз, которое продолжало падать.Проблема всегда заключалась в том, что, как написано в данный момент, программа зависала с EXE_BAD_ACCESS.И если бы я увеличил счетчик ссылок (или не выпустил его), то он работал бы отлично, но объект протекал.Я до сих пор не понимаю, как это возможно.Чтобы иметь разницу между утечкой и плохим доступом, используйте счетчик ссылок 1 (а не 2 или более).

Ответы [ 2 ]

1 голос
/ 10 августа 2011

Трудно понять это из того, что вы опубликовали, но почему бы не использовать свойства с сохранением для всех ваших распределенных данных?Например, вы возвращаете автоматически освобожденный UIImage из getSpectrogramImage, и он сохраняется в Model с вызовом self.spectrogramImage = [spectrogram getSpectrogramImage];; но нигде нет видимого свойства для спектрографического изображения, даже если вы 'снова использую себя.механизм.Это просто, что вы не удосужились опубликовать это?То, как написано, может быть автоматически выпущено, а затем, когда вы попытаетесь использовать его ...

1 голос
/ 09 августа 2011

Я не могу ответить на ваш конкретный вопрос, но это может помочь вам узнать, что происходит немного лучше. У меня есть функция "logMemUsage", которая выводит информацию об использовании вашей памяти и показывает, насколько она изменилась с прошлого раза. Если вы вызываете его раз в секунду или около того, вы можете лучше понять, как используется память в вашем приложении. Если он продолжает расти, очевидно, что есть утечка, если она идет вверх и вниз, как вы ожидаете, это хорошо, если она не идет вниз, когда вы думаете, что должны, вы увидите это. Это в github здесь в Utilities.h / .m

...