У меня проблема, когда доступ к библиотеке фотографий вызывает сбой ПОСЛЕ того, как я выбрал фотографию.
Выход журнала:
[GEPhotoControllerPopOver respondsToSelector:]: message sent to deallocated instance 0x239fbf40
Сбой происходит в Main без стека вызовов. Я получаю вышеупомянутую ошибку в журнале, только если я работаю с Guard Malloc.
GEPhotoControllerPopOver - это всплывающее окно моей библиотеки фотографий. Кажется, что что-то пытается получить к нему доступ после того, как оно было освобождено, но я не могу понять, что это за жизнь. Я устанавливаю точки останова в каждом фрагменте кода, который вызывает GEPhotoControllerPopover, и ни один из них не вызывается после выпуска GEPhotoControllerPopover.
Объявлено так:
@interface GEPhotoControllerPopOver : UIViewController < UINavigationControllerDelegate,
UIImagePickerControllerDelegate,
UIPopoverControllerDelegate
>
{
char* m_pPixelData;
int m_photoWidth;
int m_photoHeight;
int m_bytesPerPixel;
GEClient *m_pClient;
int m_longEdge;
UIImage* m_pLevelFrame;
UIImageView* m_pLevelFrameView;
UIPopoverController *m_pPopoverController;
}
- (void)UseImage:(UIImage*)theImage:(UIImagePickerController *)picker;
@end
Код для получения изображения из библиотеки фотографий:
extern UIView *g_glView;
@implementation GEPhotoControllerPopOver
- (id)init
{
return [super init];
}
- (void)loadView
{
[super loadView];
}
- (void)dealloc
{
[super dealloc];
}
- (void)SelectPhoto
{
if( [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary ] )
{
self.view = g_glView;
UIImagePickerController *pImagePicker;
pImagePicker = [[UIImagePickerController alloc] init];
pImagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
pImagePicker.delegate = self;
pImagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *) kUTTypeImage, nil];
pImagePicker.allowsEditing = NO;
m_pPopoverController = [[UIPopoverController alloc] initWithContentViewController:pImagePicker];
m_pPopoverController.delegate = self;
[m_pPopoverController setPopoverContentSize:CGSizeMake(160,160) animated:YES];
CGRect selectedRect = CGRectMake(0,0,1,1);
[m_pPopoverController presentPopoverFromRect:selectedRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[pImagePicker release];
}
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[m_pPopoverController dismissPopoverAnimated:true];
[m_pPopoverController release];
m_pPopoverController = nil;
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
[self dismissModalViewControllerAnimated:YES];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
UIImage *picture = [info objectForKey:UIImagePickerControllerOriginalImage];
[self UseImage:picture:picker];
}
}
Не думаю, что я делаю что-то слишком сумасшедшее. Я передаю данные изображения остальной части моего кода в UseImage, где я делаю копию этого, поэтому я не указываю на ту же память.
Затем я освобождаю GEPhotoControllerPopOver и никогда больше не вызываю его. К сожалению, через несколько кадров появляется ошибка, указанная выше. Только на iPad на iOS4.3. Отлично работает на iPhone (другой объект интерфейса) и на iPad с iOS3.x и iOS5.x
У кого-нибудь есть идеи?
Спасибо!
EDIT - Похоже, что удаление вызова [super dealloc] устраняет проблему. Очевидно, не лучшее решение, но, возможно, поможет выяснить, что происходит?
Я также прошел весь мой код, чтобы попытаться выяснить, где он падает, но безрезультатно. Он отклоняет всплывающее окно, проходит полный цикл рендеринга, завершает цикл рендеринга и затем падает в сборке.
РЕДАКТИРОВАТЬ 2 - Следующий код больше не дает сбой на iOS4, но утечка 32 КБ и 128 КБ памяти.
32K утечка:
0 libsystem_c.dylib calloc
1 MusicLibrary MemNewPtrClear
2 MusicLibrary ReadITImageDB
3 MusicLibrary -[MLPhotoLibrary _loadImageLibrary]
4 MusicLibrary -[MLPhotoLibrary albums]
5 PhotoLibrary -[PLPhotoLibrary albums]
6 PhotoLibrary -[PLPhotoLibrary imagePickerAlbums]
7 PhotoLibrary -[PLPhotoLibrary(Utilities) albumsForContentMode:]
8 PhotoLibrary -[PLLibraryViewController _updateAlbumsIfNecessary]
9 PhotoLibrary -[PLLibraryViewController viewWillAppear:]
10 PhotoLibrary -[PLUILibraryViewController viewWillAppear:]
11 UIKit -[UINavigationController _startTransition:fromViewController:toViewController:]
12 UIKit -[UINavigationController _startDeferredTransitionIfNeeded]
13 UIKit -[UILayoutContainerView layoutSubviews]
14 QuartzCore -[CALayer layoutSublayers]
15 QuartzCore CALayerLayoutIfNeeded
16 QuartzCore CA::Context::commit_transaction(CA::Transaction*)
17 QuartzCore CA::Transaction::commit()
18 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)
19 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
20 CoreFoundation __CFRunLoopDoObservers
21 CoreFoundation __CFRunLoopRun
22 CoreFoundation CFRunLoopRunSpecific
23 CoreFoundation CFRunLoopRunInMode
24 GraphicsServices GSEventRunModal
25 GraphicsServices GSEventRun
26 UIKit UIApplicationMain
128K утечка:
0 libsystem_c.dylib malloc
1 MusicLibrary ReadITImageDB
2 MusicLibrary -[MLPhotoLibrary _loadImageLibrary]
3 MusicLibrary -[MLPhotoLibrary albums]
4 PhotoLibrary -[PLPhotoLibrary albums]
5 PhotoLibrary -[PLPhotoLibrary imagePickerAlbums]
6 PhotoLibrary -[PLPhotoLibrary(Utilities) albumsForContentMode:]
7 PhotoLibrary -[PLLibraryViewController _updateAlbumsIfNecessary]
8 PhotoLibrary -[PLLibraryViewController viewWillAppear:]
9 PhotoLibrary -[PLUILibraryViewController viewWillAppear:]
10 UIKit -[UINavigationController _startTransition:fromViewController:toViewController:]
11 UIKit -[UINavigationController _startDeferredTransitionIfNeeded]
12 UIKit -[UILayoutContainerView layoutSubviews]
13 QuartzCore -[CALayer layoutSublayers]
14 QuartzCore CALayerLayoutIfNeeded
15 QuartzCore CA::Context::commit_transaction(CA::Transaction*)
16 QuartzCore CA::Transaction::commit()
17 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)
18 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
19 CoreFoundation __CFRunLoopDoObservers
20 CoreFoundation __CFRunLoopRun
21 CoreFoundation CFRunLoopRunSpecific
22 CoreFoundation CFRunLoopRunInMode
23 GraphicsServices GSEventRunModal
24 GraphicsServices GSEventRun
25 UIKit UIApplicationMain
Новый код:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[m_pPopoverController dismissPopoverAnimated:true];
[m_pPopoverController release];
m_pPopoverController = nil;
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
[self dismissModalViewControllerAnimated:YES];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
UIImage *picture = [info objectForKey:UIImagePickerControllerOriginalImage];
[self UseImage:picture:picker];
}
[picker dismissModalViewControllerAnimated:YES];
// [picker release]; // <- CAUSES CRASH on BOTH iOS4 and iOS5.
}
- (void)SelectPhoto
{
if( [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary ] )
{
self.view = g_glView;
UIImagePickerController *pImagePicker;
pImagePicker = [[UIImagePickerController alloc] init];
pImagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
pImagePicker.delegate = self;
pImagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *) kUTTypeImage, nil];
pImagePicker.allowsEditing = NO;
m_pPopoverController = [[UIPopoverController alloc] initWithContentViewController:pImagePicker];
m_pPopoverController.delegate = self;
[m_pPopoverController setPopoverContentSize:CGSizeMake(160,160) animated:YES];
CGRect selectedRect = CGRectMake(0,0,1,1);
[m_pPopoverController presentPopoverFromRect:selectedRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[pImagePicker release];
}
}
Вот мой код UseImage:
- (void)UseImage:(UIImage*)theImage:(UIImagePickerController *)picker
{
CGFloat width, height;
// if image came from camera, save it to photo library
if( picker.sourceType == UIImagePickerControllerSourceTypeCamera )
{
UIImageWriteToSavedPhotosAlbum(theImage, nil, nil, nil);
}
CGImageRef imageRef = [theImage CGImage];
width = CGImageGetWidth(imageRef);
height = CGImageGetHeight(imageRef);
size_t bitsPerPixel = CGImageGetBitsPerPixel( imageRef );
m_photoWidth = width;
m_photoHeight = height;
m_bytesPerPixel = bitsPerPixel / 8;
CGContextRef cgctx = CreateARGBBitmapContextPopOver(theImage.CGImage, picker.sourceType, m_pClient);
if (cgctx == NULL)
{
// error creating context
return;
}
// Get image width, height. We'll use the entire image.
size_t w = CGImageGetWidth(theImage.CGImage);
size_t h = CGImageGetHeight(theImage.CGImage);
CGRect rect = {{0,0},{w,h}};
// set the blend mode so we don't blend into the previous pixels, instead we copy over them.
CGContextSetBlendMode(cgctx, kCGBlendModeCopy);
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(cgctx, rect, theImage.CGImage);
// Now we can get a pointer to the image data associated with the bitmap
// context.
m_pPixelData = reinterpret_cast<char*>(CGBitmapContextGetData (cgctx));
m_bytesPerPixel = 4;
// any client using the photo processing package is required to implement SELECT_PHOTO to its CLIENT_STATE
m_pClient->SetState( GEClient::LOADING_PHOTO );
m_pClient->PassPixelDataFromCamera( m_pPixelData, m_photoWidth, m_photoHeight, m_bytesPerPixel );
// When finished, release the context
CGContextRelease(cgctx);
}
CGContextRef CreateARGBBitmapContextPopOver (CGImageRef inImage, UIImagePickerControllerSourceType sourceType, GEClient* pClient )
{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
// Get image width, height. We'll use the entire image.
size_t pixelsWide = CGImageGetWidth(inImage);
size_t pixelsHigh = CGImageGetHeight(inImage);
NSLog(@"Camera resolution:%lu x %lu", pixelsWide, pixelsHigh );
// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
// Use the generic RGB color space.
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
{
fprintf(stderr, "Error allocating color space\n");
return NULL;
}
// Allocate memory for image data. This is the destination in memory
// where any drawing to the bitmap context will be rendered.
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
fprintf (stderr, "Memory not allocated!");
CGColorSpaceRelease( colorSpace );
return NULL;
}
// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
context = CGBitmapContextCreate (bitmapData,
pixelsWide,
pixelsHigh,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst);
if (context == NULL)
{
free (bitmapData);
fprintf (stderr, "Context not created!");
}
// Make sure and release colorspace before returning
CGColorSpaceRelease( colorSpace );
return context;
}