写真を選択した後に写真ライブラリにアクセスするとクラッシュするという問題があります。iOS4のiPadのUIImagePickerControllerDelegateがクラッシュする(iOS5で正常に動作する)
ログ出力は次のようになります。
[GEPhotoControllerPopOver respondsToSelector:]: message sent to deallocated instance 0x239fbf40
クラッシュが無いコールスタックをメインに発生します。 GuardMallocを実行すると、上記のエラーがログに記録されます。
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のコードの残りの部分に画像データを渡しています.Imageのコピーを作成して、同じメモリを指していないようにします。
次に、GEPhotoControllerPopOverの割り当てを解除し、再度呼び出すことはありません。残念ながら、数フレーム後に上記のエラーが発生します。 iOS4.3のiPadのみ。それはiOS3.xとiOS5.xのiPhone(異なるインターフェースオブジェクト)とiPadでうまく動作します
誰でもアイデアはありますか?
ありがとうございます!
EDIT - [super dealloc]の呼び出しを削除すると、問題が消えてしまうようです。明らかに最善の解決策ではありませんが、おそらく何が起きているのか把握するのに役立ちますか? 私はすべてのコードを踏んで、無駄なクラッシュを見つけようとしました。ポップオーバーを解除し、完全なレンダリングサイクルを経て、描画サイクルを終了し、次にアセンブリが深くクラッシュします。
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)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;
}
これは動作しますが、2つのメモリリーク、つまり32Kリークと128kリークが発生します。私はそれらを主な質問に加えました。 –