Memory management 从UIImagePickerController拾取图像后发生崩溃(与内存泄漏有关?)

Memory management 从UIImagePickerController拾取图像后发生崩溃(与内存泄漏有关?),memory-management,core-data,uiimage,uiimagepickercontroller,Memory Management,Core Data,Uiimage,Uiimagepickercontroller,我一直在尝试使用UIImagePickerController最小化内存占用,但我开始认为我遇到的内存问题是由于内存管理不善造成的,而不是处理UIImagePickerController对象的特定方式 我的工作流程如下:单击“编辑图像”按钮,它将显示一个UIActionSheet。此操作表允许您删除、拍照、从库中选择或取消。如果选择“从库中选择”或“拍照”,我将分配一个UIImagePickerController实例并演示它,然后发布UIImagePickerController: 从UII

我一直在尝试使用UIImagePickerController最小化内存占用,但我开始认为我遇到的内存问题是由于内存管理不善造成的,而不是处理UIImagePickerController对象的特定方式

我的工作流程如下:单击“编辑图像”按钮,它将显示一个UIActionSheet。此操作表允许您删除、拍照、从库中选择或取消。如果选择“从库中选择”或“拍照”,我将分配一个UIImagePickerController实例并演示它,然后发布UIImagePickerController:

从UIImagePickerController获取选择后,我将2幅图像、用于缩略图的已编辑图像的大小调整版本和原始未编辑图像的800x600版本保存到关系属性转换中,使用与Recipes演示代码中相同的UIImage到PNG转换进行显示使用:调整大小方法基于中演示的方法

当我通过viewDidUnload时,我设置self.object=nil,并在dealloc期间设置[object release],但在大约10次图像更改后,我仍然收到内存警告,大约20次崩溃。这让我相信,我没有以正确的方式从记忆中获得完整的图像。我错过了什么

第二个问题是,相机源比相册源使用的内存要多得多吗?在使用相机时,我往往会发生更多的碰撞

-编辑- 开始悬赏以获取任何关于我可能处理错误的信息。我会更新这篇文章,回答我不清楚的任何问题。在这件事上我真是束手无策

-编辑2- 重新修改代码以考虑Chrisr的建议,并实施GCD以提高可用性。这是否和这个过程一样高效?仍然收到内存警告,并且在内存中出现了大约20个图像的崩溃。我敢肯定,昂贵的UIImage大小调整和使用UIImagePickerController的组合正在扼杀CPU,但我无法想象每个应用程序都在处理UIImagePickerController周围的不确定性。我的内存占用大约是2兆。我一直在假设这是一笔很大的开销。我应该进一步减少这个足迹吗

以下是修改后的代码:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{

    [self dismissModalViewControllerAnimated:YES];

    if (object.imagePath != nil) {
        [self deleteImages];
    }
    dispatch_queue_t image_queue;
    image_queue = dispatch_queue_create("com.gordonfontenot.app", NULL);

    dispatch_async(image_queue, ^{
    
        NSDate *now = [NSDate date];
    
        NSDateFormatter *f = [[NSDateFormatter alloc] init];
        [f setDateFormat:@"yyyyMMDDHHmmss"];
    
        NSString *imageName = [NSString stringWithFormat:@"Image-%@-%i", [f stringFromDate:now], arc4random() % 100];
        NSString *thumbName = [NSString stringWithFormat:@"%@-thumb", imageName];
    
        [f release];
    
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
    
        NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:imageName];
        NSString *thumbPath = [documentsDirectory stringByAppendingPathComponent:thumbName];
    
        NSData *thumbImageData = UIImagePNGRepresentation([UIImageManipulator scaleImage:[info objectForKey:@"UIImagePickerControllerEditedImage"] toSize:CGSizeMake(120, 120)]);
        [thumbImageData writeToFile:thumbPath atomically:NO];
        dispatch_async(dispatch_get_main_queue(), ^{
            object.thumbPath = thumbPath;
            [self setupImageButton];
            imageButton.enabled = NO;
            [self setupChooseImageButton];
        });
        NSData *fullImageData = UIImagePNGRepresentation([UIImageManipulator scaleImage:[info objectForKey:@"UIImagePickerControllerOriginalImage"] toSize:CGSizeMake(800, 600)]);
        [fullImageData writeToFile:fullPath atomically:NO];

        dispatch_async(dispatch_get_main_queue(), ^{
            imageButton.enabled = YES;
            object.imagePath = fullPath;
        });
    
        if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            UIImageWriteToSavedPhotosAlbum([info objectForKey:@"UIImagePickerControllerOriginalImage"], self, nil, nil);
        }
    
    });
    dispatch_release(image_queue);
}

在处理UIImagePickerController时,内存警告非常常见。使用相机时尤其如此。请记住,虽然磁盘上的JPG或PNG可能只有几MB,但用于绘制图像的未压缩内存位图使用的空间要多得多

没有什么是你一定做错了,但是可以做一些改进:

与其将图像字节存储在核心数据中,为什么不将图像写入磁盘并将文件路径存储在数据库中

您能找到一种方法直接管理它们的生命周期并更快地发布它们,而不是使用这么多自动释放的图像吗


最好的办法可能是在处理完图像后尽快将其写入磁盘,并释放它们正在使用的内存。然后使用核心数据而不是原始数据存储它们的位置。

谢谢您的建议。我已经更新了帖子以显示我现在使用的代码。你介意再看一下吗?代码看起来不错。你能更具体地说明你遇到的车祸吗?使用相机时收到内存警告是完全正常的,但是如果你的内存占用像你说的那么小,那么就不会发生任何崩溃。在加载和卸载很少激活的视图时,内存警告处理是否有问题?也许是某种种族状况?这是相当一致的。我得到了内存警告,首先是一些1级警告,然后到了最后,我得到了2级警告。然后,在15到20个图像选择之后,我得到了崩溃。我现在在想,可能是由于与UIImagePickerController无关的缓慢内存爬行导致崩溃。看起来UIImagePickerController向内存添加了近15兆。我从2兆开始,但我还没有测试过这个怪物有多坏。我会记下这个作为答案,因为你真的帮助了我。非常感谢。我的应用程序在从gallery中选择重图片时崩溃。将UIImage转换为NSData时。。有什么建议吗
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{

    [self dismissModalViewControllerAnimated:YES];

    NSManagedObject *oldImage = object.imageFull;
    if (oldImage != nil)
    {
        [object.managedObjectContext deleteObject:oldImage];
    }

    NSManagedObject *image = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:object.managedObjectContext];
    object.imageFull = image;

    UIImage *rawImage = [info objectForKey:@"UIImagePickerControllerOriginalImage"];

    CGSize size = CGSizeMake(800, 600);

    UIImage *fullImage = [UIImageManipulator scaleImage:rawImage toSize:size];

    [image setValue:fullImage forKey:@"imageFull"];

    UIImage *processedImage = [UIImageManipulator scaleImage:[info objectForKey:@"UIImagePickerControllerEditedImage"] toSize:CGSizeMake(75, 75)];
    object.objectImage = processedImage;
    [self setupImageButton];
    [self setupChooseImageButton];

    rawImage = nil;
    fullImage = nil;
    processedImage = nil;
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{

    [self dismissModalViewControllerAnimated:YES];

    if (object.imagePath != nil) {
        [self deleteImages];
    }
    dispatch_queue_t image_queue;
    image_queue = dispatch_queue_create("com.gordonfontenot.app", NULL);

    dispatch_async(image_queue, ^{
    
        NSDate *now = [NSDate date];
    
        NSDateFormatter *f = [[NSDateFormatter alloc] init];
        [f setDateFormat:@"yyyyMMDDHHmmss"];
    
        NSString *imageName = [NSString stringWithFormat:@"Image-%@-%i", [f stringFromDate:now], arc4random() % 100];
        NSString *thumbName = [NSString stringWithFormat:@"%@-thumb", imageName];
    
        [f release];
    
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
    
        NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:imageName];
        NSString *thumbPath = [documentsDirectory stringByAppendingPathComponent:thumbName];
    
        NSData *thumbImageData = UIImagePNGRepresentation([UIImageManipulator scaleImage:[info objectForKey:@"UIImagePickerControllerEditedImage"] toSize:CGSizeMake(120, 120)]);
        [thumbImageData writeToFile:thumbPath atomically:NO];
        dispatch_async(dispatch_get_main_queue(), ^{
            object.thumbPath = thumbPath;
            [self setupImageButton];
            imageButton.enabled = NO;
            [self setupChooseImageButton];
        });
        NSData *fullImageData = UIImagePNGRepresentation([UIImageManipulator scaleImage:[info objectForKey:@"UIImagePickerControllerOriginalImage"] toSize:CGSizeMake(800, 600)]);
        [fullImageData writeToFile:fullPath atomically:NO];

        dispatch_async(dispatch_get_main_queue(), ^{
            imageButton.enabled = YES;
            object.imagePath = fullPath;
        });
    
        if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            UIImageWriteToSavedPhotosAlbum([info objectForKey:@"UIImagePickerControllerOriginalImage"], self, nil, nil);
        }
    
    });
    dispatch_release(image_queue);
}