2012-02-19 5 views
0

사진을 선택한 후 사진 라이브러리에 액세스하면 오류가 발생하는 문제가 있습니다.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 코드

답변

0

나는 여기서 야생 찌르다. 당신의 코드는 꽤 좋아 보인다. 피곤해서 뭔가 빠져있을 수도 있지만 테스트를 위해서 "[pImagePicker release]; 그리고 무슨 일이 일어나는 지보십시오. 그것은 최종 권장 사항은 아니지만 노력할 가치가 있습니다.

이미지 선택기와 비슷한 점을 발견하고 릴리스를 변경 한 곳에서 문제가 해결되었습니다.

+0

이것이 작동하는 동안, 두 개의 메모리 누수, 즉 32K 누출과 128K 누출이 발생합니다. 나는 그것들을 주된 질문에 덧붙였다. –

0

popover를 닫을 때 popover 컨트롤러의 delegate를 nil로 설정하십시오. 프레임 워크 코드에는 공개 된 후 viewController에서 대리자 메서드에 액세스하려고하는 것이 있다고 생각합니다. Popover에서 Delegate를 삭제하면 나에게이 문제가 해결되었고 Popover를 적절하게 해제 할 수있었습니다. 4에 왜 그런 일이 일어나는지 전혀 모르겠지만 거기에 가면됩니다. 다행히도 한 달 후에도 문제가 해결 될 수 있기를 바랍니다.

관련 문제