Processing UIImagePickerController
2013-04-19 14:18
459 查看
The UIImagePickerController class has been the developer’s best friend and worst enemy since its introduction into the iPhone SDK in iOS 2.0. For those who have not used it, this class
provides a way for an application to have the user select and return an image, whether it be existing from the device’s library or fresh from the camera; this image may then be included into the application in some manner. Today we are going to discuss a problem
that is almost as common as the use of the class itself! I’m talking about memory warnings and crashes.
I think one of the most common issues stems from developers trying to do something akin to the following code:
Translated into plain text, “as soon as the user selects an image and we get a callback, display that image in some view and move on”. Eek! Most often (even on the high-powered iPhone
4), this will result in one of the two following behaviors:
Your app will crash…hard.
After the user dismisses the picker, you get a memory warning, and the view controller that presented the picker looks as though it has been reloaded from scratch (…because it has)
This will happen most often with images from the camera, but as images stored in the library get larger and larger you will see it happen there as well. The issue is a combination
of memory recovery behavior and processing power.
The first thing many developers notice is the memory warning that arises in the console circa the time of the failure…and so they tend to focus on it. Because it’s the only visual
clue they have to start diagnostics from. The memory warning is usually marked with a “Level=1″, which indicates it’s a warning and not critical or some other level. Even when your application is running perfectly, you will likely still get these warnings
every time you use an image picker…and that’s okay! However, what the warning does signal to you is that the wrong choice of your next move will result in one of the two behaviors above.
On an iPhone 3GS, for example, the camera is 3 megapixel. UIImagePickerController gives you the full image back when you retrieve it in the delegate callback (that’s 2048 x 1536 pixels)!
Storing this much image data in memory is one thing, but forcing your UI thread to try and do something with it will only spell disaster. iOS will try to first free up as much memory as it can by releasing view controller objects (symptom #2). If it is unsuccessful,
dire circumstances await (symptom #1).
What you do with the image (display it, save it to disk, etc.) depends on your application. But there are two universal truths about the image data that comes back:
The image SHOULD be scaled down
The processing MUST not be done on the main/UI thread
There is a really great piece of useful code in the community that I cannot take credit for, but I will post here for convenience. This code uses UIKit methods to resize and scale
down an image.
Even if you intend to save the full image to disk and you want to display a preview, that preview should not be larger than the viewport of the device (320×480 or 640×960). Forcing
UIKit to scale the image for you at runtime with a call tosetImage: is a bad plan.
Many of you may have looked at the previous method and asked why an NSAutoreleasePool was
created; that is because of the next step. Even if you have the presence of mind to scale down your image before displaying it, if you try to do so on the main thread you will end up with the same results as if you had left that job up to iOS. Because of
this, the scaling method we have written should be dispatched into a background thread, and our delegate method gets modified like so:
You may also want to consider popping up a progress dialog or something during the operation (Apple does this as well, try taking a picture for your contacts), as it can take a few
seconds.
There, now we have a working example of how to properly handle picked images that we want to display in our applications. Hopefully this will keep some of you from going bald too soon.
转帖:http://wiresareobsolete.com/wordpress/tag/uiimagepickercontroller/
provides a way for an application to have the user select and return an image, whether it be existing from the device’s library or fresh from the camera; this image may then be included into the application in some manner. Today we are going to discuss a problem
that is almost as common as the use of the class itself! I’m talking about memory warnings and crashes.
Images on Display
I think one of the most common issues stems from developers trying to do something akin to the following code:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | - (void)someActionMethod { UIImagePickerController *controller = [[UIImagePickerController alloc] init]; [controller setDelegate:self]; [self presentModalViewController:controller animated:YES]; [controller release]; } - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { [[picker parentViewController] dismissModalViewControllerAnimated:YES]; UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; [myImageView setImage:image]; } |
Translated into plain text, “as soon as the user selects an image and we get a callback, display that image in some view and move on”. Eek! Most often (even on the high-powered iPhone
4), this will result in one of the two following behaviors:
Your app will crash…hard.
After the user dismisses the picker, you get a memory warning, and the view controller that presented the picker looks as though it has been reloaded from scratch (…because it has)
This will happen most often with images from the camera, but as images stored in the library get larger and larger you will see it happen there as well. The issue is a combination
of memory recovery behavior and processing power.
My Brain Hurts
The first thing many developers notice is the memory warning that arises in the console circa the time of the failure…and so they tend to focus on it. Because it’s the only visualclue they have to start diagnostics from. The memory warning is usually marked with a “Level=1″, which indicates it’s a warning and not critical or some other level. Even when your application is running perfectly, you will likely still get these warnings
every time you use an image picker…and that’s okay! However, what the warning does signal to you is that the wrong choice of your next move will result in one of the two behaviors above.
On an iPhone 3GS, for example, the camera is 3 megapixel. UIImagePickerController gives you the full image back when you retrieve it in the delegate callback (that’s 2048 x 1536 pixels)!
Storing this much image data in memory is one thing, but forcing your UI thread to try and do something with it will only spell disaster. iOS will try to first free up as much memory as it can by releasing view controller objects (symptom #2). If it is unsuccessful,
dire circumstances await (symptom #1).
What’s the Right Move?
What you do with the image (display it, save it to disk, etc.) depends on your application. But there are two universal truths about the image data that comes back:The image SHOULD be scaled down
The processing MUST not be done on the main/UI thread
Scaling
There is a really great piece of useful code in the community that I cannot take credit for, but I will post here for convenience. This code uses UIKit methods to resize and scaledown an image.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | - (void)useImage:(UIImage *)image { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Create a graphics image context CGSize newSize = CGSizeMake(320, 480); UIGraphicsBeginImageContext(newSize); // Tell the old image to draw in this new context, with the desired // new size [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; // Get the new image from the context UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); // End the context UIGraphicsEndImageContext(); [userPhotoView setImage:newImage]; [pool release]; } |
Even if you intend to save the full image to disk and you want to display a preview, that preview should not be larger than the viewport of the device (320×480 or 640×960). Forcing
UIKit to scale the image for you at runtime with a call tosetImage: is a bad plan.
Backround Threading
Many of you may have looked at the previous method and asked why an NSAutoreleasePool wascreated; that is because of the next step. Even if you have the presence of mind to scale down your image before displaying it, if you try to do so on the main thread you will end up with the same results as if you had left that job up to iOS. Because of
this, the scaling method we have written should be dispatched into a background thread, and our delegate method gets modified like so:
1 2 3 4 5 6 7 8 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { [[picker parentViewController] dismissModalViewControllerAnimated:YES]; UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; [NSThread detachNewThreadSelector:@selector(useImage:) toTarget:self withObject:image]; } |
You may also want to consider popping up a progress dialog or something during the operation (Apple does this as well, try taking a picture for your contacts), as it can take a few
seconds.
Conclusion
There, now we have a working example of how to properly handle picked images that we want to display in our applications. Hopefully this will keep some of you from going bald too soon.转帖:http://wiresareobsolete.com/wordpress/tag/uiimagepickercontroller/
相关文章推荐
- UIImagePickerController的使用
- iOS之UIImagePickerController显示中文界面
- Attempt to present <UIImagePickerController: 0x1848de00> on <UINavigationController: 0x17e6ed50> wh
- UIImagePickerController
- UIImagePickerController 视频录制操作,视频大小,时间长度
- ios调用UIImagePickerController crash的问题
- UIImagePickerController 图像选取器--在iPhone中调用照相机、照片库—IOS开发
- UIImagePickerController 图像选取器--在iPhone中调用照相机、照片库—IOS开发
- IOS开发之相册拾取器UIImagePickerController
- UIImagePickerController
- UIImagePickerController及iphone的触摸判断
- IOS开发之小实例--使用UIImagePickerController创建一个简单的相机应用程序
- UIImagePickerController 图像选取器--在iPhone中调用照相机、照片库
- iOS UIImagePickerController 图片拾取器
- UIImagePickerController在ios10环境一打开就crash的问题
- 使用UIImagePickerController拍照和视频录制
- Assigning to ‘id<UINavigationControllerDelegate,UIImagePickerControllerDelegate>’ from incompatible
- UIImagePickerController
- UIImagePickerController Class
- Swift学习笔记(4)使用UIImagePickerController实现从设备图片库和照相机获取图片