在使用仪器进行分析后,我发现当使用较低分辨率的前置摄像头图像时,我的应用程序内存占用大约保持在20-25 MB,但使用后置摄像头时,每次视图更改都会增加33 MB左右,直到崩溃大约350 MB(在一个4S)
下面是我用来处理将照片保存到文档目录,然后读取该文件位置以将图像设置为UIImageView的代码.此代码的“读取”部分通过多个视图控制器(viewDidLoad)进行回收,以便将我保存的图像设置为每个视图中的背景图像.
我删除了所有的图像修改代码,将其剥离到试图隔离问题的最小值,我似乎无法找到它.就目前而言,所有应用程序都会在第一个视图中拍摄照片,然后将该照片用作大约10个以上视图的背景图像,并在用户浏览视图堆栈时进行分配.
现在显然更高分辨率的照片会占用更多内存,但我不明白的是,为什么低分辨率照片似乎没有使用越来越多的内存,而高分辨率照片不断使用越来越多直到崩溃.
我如何保存和阅读图像:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"]; jpgData = UIImageJPEGRepresentation(image,1); NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES); NSString *documentsPath = [paths objectAtIndex:0]; filePath = [documentsPath stringByAppendingPathComponent:@"image.jpeg"]; [jpgData writeToFile:filePath atomically:YES]; [self dismissModalViewControllerAnimated:YES]; [disableNextButton setEnabled:YES]; jpgData = [NSData dataWithContentsOfFile:filePath]; UIImage *image2 = [UIImage imageWithData:jpgData]; [imageView setImage:image2]; }
现在我知道我可以在保存之前尝试缩放图像,我计划在接下来查看,但我不明白为什么这不起作用.也许我错误地认为ARC在离开堆栈顶部时会自动释放视图及其子视图.
任何人都可以解释为什么我要存储我的设备内存? (希望简单的事情,我完全忽略了)我是不是设法把ARC抛到窗外?
编辑:我如何在其他视图中调用图像
- (void)loadBackground { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES); NSString *documentsPath = [paths objectAtIndex:0]; NSString *filePath = [documentsPath stringByAppendingPathComponent:@"image.jpeg"]; UIImage *image = [UIImage imageWithContentsOfFile:filePath]; [backgroundImageView setImage:image]; }
如何建立视图控制器之间的导航:
编辑2:
我的基本声明是什么样的:
#import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> @interface PhotoPickerViewController : UIViewController <UIImagePickerControllerDelegate,UINavigationControllerDelegate> { IBOutlet UIImageView *imageView; NSData *jpgData; NSString *filePath; UIImagePickerController *imagePicker; IBOutlet UIBarButtonItem *disableNextButton; } @end
如果相关,我如何调用我的图像选择器:
- (void)callCameraPicker { if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == YES) { NSLog(@"Camera is available and ready"); imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; imagePicker.delegate = self; imagePicker.allowsEditing = NO; imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice *device in devices) { if([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.0) { imagePicker.cameraDevice = UIImagePickerControllerCameraDeviceFront; } } imagePicker.modalTransitionStyle = UIModalTransitionStyleCoverVertical; [self presentModalViewController:imagePicker animated:YES]; } else { NSLog(@"Camera is not available"); UIAlertView *cameraAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your device doesn't seem to have a camera!" delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:nil]; [cameraAlert show]; } }
编辑3:我记录了viewDidUnload,它实际上没有被调用,所以我现在在viewWillAppear中调用loadBackground并在viewDidDisappear中使我的backgroundImageView为nil.我希望这会有所帮助,但没有任何区别.
- (void)viewWillAppear:(BOOL)animated { [self loadBackground]; } - (void)viewDidDisappear:(BOOL)animated { NSLog(@"ViewDidDisappear"); backgroundImageView = nil; }
解决方法
UIImage是图像数据的高级表示 – 仅此一点,它在显示数据方面没有任何作用.
UIImageView与UIImage配合使用,可以显示图像.
UIImageView的多个实例无法显示相同的UIImage.这是好的和有效的,因为只有一个内存中的图像数据表示,由多个视图共享.
您似乎要做的是通过从磁盘加载每个视图为其创建一个新的UIImage.因此,这在两个方面是一个糟糕的通用设计:一遍又一遍地实例化同一个UIImage,并重复从磁盘重新加载相同的图像数据.
你的内存问题实际上是一个单独的问题,你没有正确地释放你加载到UIImage对象和UIImageViews中的图像数据.
从理论上讲,你应该能够从UIImagePickerController获取你得到的第一个UIImage,并简单地将该引用传递给你的视图,而无需从磁盘重新加载.
如果您需要从磁盘保存和重新加载,因为更高级别的功能要求(例如,因为用户正在更改图像并且您希望保留它),您需要确保完全拆除以前的图像UIView,从它的视图层次结构中删除它.在dealloc方法中为视图设置断点以确认它被删除和解除分配是有帮助的,并确保将任何iVar引用设置为子视图(看起来你的backgroundImageView是iVar)都设置为nil.如果你没有正确地拆除那个backgroundImageView,它将继续保持对你设置为它的image属性的UIImage的引用.