2012-02-19 54 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中的其餘代碼,在那裏創建它的副本,因此我沒有指向相同的內存。

然後我釋放GEPhotoControllerPopOver並且再也不會調用它。不幸的是幾幀後,發生上述錯誤。只在iOS4.3的iPad上。它適用於iPhone(不同的界面對象)和iPad上的iOS3.x和iOS5.x

任何人有任何想法?

謝謝!

編輯 - 看起來,刪除對[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; 
} 

回答

0

我在這裏採取野性刺。你的代碼看起來相當不錯,我很累,可能會丟失一些東西,但僅用於測試,刪除行「[pImagePicker發佈];」並看看會發生什麼。這不是最終的建議,但值得嘗試。

我碰到了類似於圖像選擇器的東西,並改變了我在發佈版本的位置,並解決了問題。

+0

儘管如此,它會產生兩個內存泄漏,32K泄漏和128k泄漏。我將它們添加到主要問題中。 – 2012-02-20 10:41:58

0

當您關閉彈出窗口時,將彈出窗口控制器的代理設置爲零。我認爲在框架代碼中有一些東西試圖在viewController發佈後訪問委託方法。從popover刪除委託解決了這個問題,我能夠正確釋放popover。不知道爲什麼它只發生在4,但你去了。希望能夠解決您的問題,即使是一個月後。

相關問題