Память Предупреждение UIImagepickerController IOS 7
Может кто-нибудь помочь мне в этом вопросе, я немного новичок в объектах c и iOS. Я работал над этим, но я не могу понять, как исправить эту проблему. Мое приложение действительно просто, но только запустите камеру, сделайте снимки и отправьте их по электронной почте на наш сервер. Этот код работал отлично в iOS6.
Когда я делаю снимки, моя память - это рост кучи при каждом захвате экрана, и я получаю "Предупреждение о принимаемой памяти" и, наконец, завершено из-за давления памяти. -
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self.popoverController2 dismissPopoverAnimated:true];
NSString *mediaType = [info
objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
_image = [info
objectForKey:UIImagePickerControllerOriginalImage];
_image = [self fixrotation:_image]; //<----- increased memory when UIImageWriteToSavedPhotosAlbum is uncommented IF is comment it doesn't increased memory but after some pictures I start to get "Received Memory Warning" message until the app Crash.
if (_newMedia){
UIImageWriteToSavedPhotosAlbum(_image,
self,@selector(image:finishedSavingWithError:contextInfo:),
nil);
[self dismissViewControllerAnimated:NO completion:nil];
[self performSegueWithIdentifier:@"SeleccionadoCameraR" sender:self];
}else{
[self performSegueWithIdentifier:@"SeleccionadoCameraR" sender:self];
}
}
}
- (UIImage *)fixrotation:(UIImage *)image{
if (image.imageOrientation == UIImageOrientationUp) return image;
CGAffineTransform transform = CGAffineTransformIdentity;
switch (image.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, image.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, image.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
break;
}
switch (image.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, image.size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, image.size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationUp:
case UIImageOrientationDown:
case UIImageOrientationLeft:
case UIImageOrientationRight:
break;
}
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
CGContextRef ctx = CGBitmapContextCreate(NULL, image.size.width, image.size.height,
CGImageGetBitsPerComponent(image.CGImage), 0,
CGImageGetColorSpace(image.CGImage),
CGImageGetBitmapInfo(image.CGImage));
CGContextConcatCTM(ctx, transform);
switch (image.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
// Grr...
CGContextDrawImage(ctx, CGRectMake(0,0,image.size.height,image.size.width), image.CGImage);
break;
default:
CGContextDrawImage(ctx, CGRectMake(0,0,image.size.width,image.size.height), image.CGImage); //when I use instruments it shows that My VM is because of this
break;
}
// And now we just create a new UIImage from the drawing context
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);//also this line in Instruments
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
return img;
}
возможно, это управление памятью. Я буду благодарен за вашу помощь.
Ответы
Ответ 1
Вы находитесь на правильном пути с помощью метода fixRotation
. Однако вы также должны изменить размер изображения. В противном случае изображение будет огромным, ~ 30 МБ (в зависимости от устройства).
Оформить заказ это сообщение в блоге о том, как правильно изменить размер изображений. В частности, файлы категорий UIImage
, которые вы хотите, следующие:
UIImage + Resize.h
UIImage + Resize.m
Это также хорошая идея сделать это в фоновом потоке. Что-то вроде этого
- (void)imagePickerController:(UIImagePickerController *)imagePicker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Dismiss the image picker first to free its memory
[self dismissViewControllerAnimated:YES completion:nil];
UIImage *originalImage = info[UIImagePickerControllerOriginalImage];
if (!originalImage)
return;
// Optionally set a placeholder image here while resizing happens in background
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Set desired maximum height and calculate width
CGFloat height = 640.0f; // or whatever you need
CGFloat width = (height / originalImage.size.height) * originalImage.size.width;
// Resize the image
UIImage * image = [originalImage resizedImage:CGSizeMake(width, height) interpolationQuality:kCGInterpolationDefault];
// Optionally save the image here...
dispatch_async(dispatch_get_main_queue(), ^{
// ... Set / use the image here...
});
});
}
Ответ 2
UIImageWriteToSavedPhotosAlbum метод использует 30M + память на iOS7.Это не о вашем методе изменения размера или фиксации.
Ответ 3
Я исправил эту проблему с помощью ответа JRG-Developer здесь
с небольшими изменениями:
Я использую категории для фиксации ориентации изображения и его масштабирования перед представлением
и когда это делается, я называю Weak Self, чтобы назначить это масштабированное и фиксированное изображение в мое изображение)
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *lvImage = [info objectForKey:UIImagePickerControllerOriginalImage];
//CGSize pickedImageSize = lvImage.size;
if (postHandler == nil)
{
postHandler = [[PostHandler alloc] init];
}
//_postItemImageView.image = lvImage;
//postHandler.wholeScreenImage = lvImage;// to proceed editing, cropping, tagging ...
//_postItemImageView.image = postHandler.wholeScreenImage; set in viewWillAppear
__weak PostPrepareViewController *weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
// Resize the image
UIImage * scaledImage = [[lvImage imageByScalingAndCroppingForSize:_postItemImageView.frame.size] fixOrientation];
// Optionally save the image here...
//CGSize scaledimageSize = scaledImage.size;
dispatch_async(dispatch_get_main_queue(), ^
{
postHandler.wholeScreenImage = scaledImage;
[weakSelf didScaleDownImage];
});
});
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
[self.popOver dismissPopoverAnimated:YES];
}
else
{
[self dismissViewControllerAnimated:YES completion:nil];
}
}
и ниже:
-(void) didScaleDownImage
{
_postItemImageView.image = postHandler.wholeScreenImage;
}
код масштабирования был взят из сети:
-(UIImage *)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
UIImage *sourceImage = self;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO)
{
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor > heightFactor)
{
scaleFactor = widthFactor; // scale to fit height
}
else
{
scaleFactor = heightFactor; // scale to fit width
}
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor > heightFactor)
{
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
}
else
{
if (widthFactor < heightFactor)
{
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
}
UIGraphicsBeginImageContext(targetSize); // this will crop
//UIGraphicsBeginImageContextWithOptions(targetSize, 1.0, 0.0);
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
if(newImage == nil)
{
NSLog(@"could not scale image");
}
//pop the context to get back to the default
UIGraphicsEndImageContext();
return newImage;
}
и код для изменения (фиксации) ориентации изображения был также взят из сети:
- (UIImage *)fixOrientation
{ // No-op if the orientation is already correct
if (self.imageOrientation == UIImageOrientationUp) return self;
// We need to calculate the proper transformation to make the image upright.
// We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
CGAffineTransform transform = CGAffineTransformIdentity;
switch (self.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, self.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
default:
break;
}
switch (self.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
default:
break;
}
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
CGImageGetBitsPerComponent(self.CGImage), 0,
CGImageGetColorSpace(self.CGImage),
CGImageGetBitmapInfo(self.CGImage));
CGContextConcatCTM(ctx, transform);
switch (self.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
// Grr...
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
break;
default:
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
break;
}
// And now we just create a new UIImage from the drawing context
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
CGContextRelease(ctx);
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGImageRelease(cgimg);
//
return img;
}
пожалуйста, не будьте жестокими в том, чтобы ругать, если что-то выглядит фиктивным) I-m junior на данный момент)
Для ответа ниже - это то, что вам лучше масштабировать изображение - чтобы использовать меньше памяти, но не просто сохранить большое изображение 4 МБ на диск. В самом начале у меня также были проблемы с памятью - он ел 30 Мб на фотографию сигл - и мне приходилось снимать по 2 фотографии один за другим... теперь он работает отлично и плавно.
Исправление ориентации необязательно, но я бы порекомендовал все равно уменьшить масштаб фотографии - измените ее размер до меньшего размера.