【发布时间】:2012-02-19 16:01:49
【问题描述】:
我有一个问题,在我选择照片后访问照片库会触发崩溃。
日志输出为:
[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 并且不再调用它。不幸的是,几帧之后发生了上述错误。仅在 iOS4.3 上的 iPad 上。它在 iPhone(不同的界面对象)和带有 iOS3.x 和 iOS5.x 的 iPad 上运行良好
有人有什么想法吗?
谢谢!
编辑 - 似乎删除对 [super dealloc] 的调用会使问题消失。显然不是最好的解决方案,但可能有助于弄清楚发生了什么? 我还逐步检查了我的所有代码,试图找出崩溃的地方,但无济于事。它关闭弹出框,经历一个完整的渲染周期,完成绘制周期,然后在程序集深处崩溃。
编辑 2 - 以下代码在 iOS4 上不再崩溃,但会泄漏 32k 和 128k 的内存。
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;
}
【问题讨论】:
标签: objective-c ipad ios4 photo