사진을 선택한 후 사진 라이브러리에 액세스하면 오류가 발생하는 문제가 있습니다.iOS4에서 iPad의 UIImagePickerControllerDelegate가 충돌 함 (iOS5에서 정상적으로 작동 함)
로그 출력은 다음과 같습니다
[GEPhotoControllerPopOver respondsToSelector:]: message sent to deallocated instance 0x239fbf40
충돌없이 호출 스택과 함께 홈페이지에 발생합니다. 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의 나머지 코드에 이미지 데이터를 전달합니다. UseImage에서는 복사본을 만들어 동일한 메모리를 가리키고 있지 않습니다.
그런 다음 GEPhotoControllerPopOver를 할당 해제하고 다시 호출하지 마십시오. 불행히도 몇 프레임 후에 위의 오류가 발생합니다. iOS4.3의 iPad에서만 가능합니다. 그것은 iOS3.x 및 iOS5.x와 아이폰 (다른 인터페이스 개체) 및 iPad에서 잘 작동
아무도 아이디어가 있으십니까?
감사합니다.
EDIT - [super dealloc]에 대한 호출을 제거하면 문제가 사라집니다. 분명히 최선의 해결책은 아니지만 어쩌면 무슨 일이 일어나는지 파악하는 데 도움이 될 것입니다. 나는 또한 모든 코드를 밟아서 아무 쓸모가없는 곳을 찾아 냈습니다. 그것은 popover를 취소하고, 전체 렌더링주기를 거치며, 드로 사이클을 완료 한 다음, 어셈블리에서 심하게 충돌합니다.
EDIT 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)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;
}
: 여기
-(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 코드
이것이 작동하는 동안, 두 개의 메모리 누수, 즉 32K 누출과 128K 누출이 발생합니다. 나는 그것들을 주된 질문에 덧붙였다. –