I have a simple iPhone application.
I display a UIImagePicker, and let the user select an image.
I then execute some code on the image, and want this code to execute after the UIImagePicker has been dismissed.
EDIT: updated code, problem remains:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSData* data = UIImagePNGRepresentation([info objectForKey:#"UIImagePickerControllerOriginalImage"]);
[[picker parentViewController] dismissModalViewControllerAnimated:TRUE];
[self executeSomeCode: data];
}
However, when I run the code, it hangs on the UIImagePicker to run my code, and then the UIImagePicker is visually dismissed after said code has executed.
Any ideas?
I realize this isn't the most graceful of answers. I've had similar problems before (trying to do visual things in viewDidAppear that wasn't working). I found that by calling performSelector:withObject:afterDelay: caused my visual effects to be seen.
So in your case it would be:
[self performSelector:#selector(executeSomeCode:) withObject:data afterDelay:0];
I have no idea if this will work for you (or why it worked for me).
It shouldn't be necessary to use a background method, but you can try this approach:
- (void)_processImage:(UIImage*)image
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// convert to PNG data here, etc.
// this is background, remember to manipulate UI in main thread
// Example: [self.anImageView performSelectorOnMainThread:#selector(setImage:) withObject:image waitUntilDone:NO];
[pool release];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
UIImage *picked = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[self performSelectorInBackground:#selector(_processImage:) withObject:[[picked retain] autorelease]];
}
http://developer.apple.com/iphone/library/documentation/uikit/reference/UIImagePickerControllerDelegate_Protocol/UIImagePickerControllerDelegate/UIImagePickerControllerDelegate.html
I believe your call was deprecated in iOS3
You might try
(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
and the get the data from the image before dismissing the viewController
NSData *data = UIImageJPEGRepresentation( [info objectForKey:#"UIImagePickerControllerOriginalImage"] , 1.0);
[self dismissModalViewControllerAnimated:TRUE];
[self executeSomeCode:img];
I don't think you are hanging where you think you are. UIImagePNGRepresentation takes quite some time to perform as far as I know (UIImageJPEGRepresentation is much faster, if you don't mind not being lossless). You could pass the dictionary into your method and obtain the NSData you need in there.
Your second problem is that your code is synchronous, no matter how soon you tell your controller to dismiss, it will wait your long code to run. To schedule your heavy code on the next run loop iteration and let the controller be dismissed, use a 0ms delay to perform it.
I would change your code to this:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
[self performSelector:#selector(executeSomeCode:) withObject:info afterDelay:0.0f];
}
Related
I have created a app which pick image from Camera and on didFinishPickingMediaWithInfo pass this to another view and load this view. I think code is okay but it takes appx 15-20 seconds to display second view. So please let me know how can I fix this loading issue.
My code block is :
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
[NSThread detachNewThreadSelector:#selector(switchToSecondView:) toTarget:self withObject:info];
}
-(void) switchToSecondView:(NSDictionary *)info
{
UIImage *image = [info
objectForKey:UIImagePickerControllerOriginalImage];
secController =[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secController.myimage = image;
AppDelegate *appDelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.navController pushViewController:secController animated:NO];
}
Thanks,
Laxmilal Menaria
UiKit is [overwhelmingly] safe to use on the main thread only. Your work in switchToSecindView: is happening on a background thread. Behaviour is therefore undefined.
Likely what's happening is that UIKit is failing to notice your changes until it happens to be doing some other processing.
I am new to iphone development.I am implementing the UIImagePickerController in my application .When didFinishPickingMediaWithInfo delegate is called that is when choose button is clicked its having some delay .My code is as follows
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
LGViewHUD* hud = [LGViewHUD defaultHUD];
hud.activityIndicatorOn=YES;
hud.bottomText=#"Login..";
[hud showInView:picker.view];
[self performSelectorInBackground:#selector(pickerFunction:) withObject:info];
}
- (void) pickerFunction :(NSDictionary *)info
{
profilePicture.image = [info objectForKey:#"UIImagePickerControllerEditedImage"];
[imgPicker dismissModalViewControllerAnimated:YES];
}
I am trying to bring a hud on choose button action but it comes only after some delay.Can any one suggest me a methods for this implementation.
Thanks in advance..
I don't think there is anything to do about it.
I've had the problem myself, and it seems that the lag is coming from UIImagePickerController calling the delegate method "didFinishPickingMediaWithInfo". Once it gets to that method, everything runs quickly. It doesn't matter what code you put into "didFinishPickingMediaWithInfo". The lag time happens BEFORE that method is even called.
I even tried this, which does nothing except dismiss the controller.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[self dismissModalViewControllerAnimated:YES];
}
and it still took a few seconds do dismiss the UIImagePickerController.
I had a similar delay occurring with this delegate. Turns out the didFinishPickingMediaWithInfo isn't called until the image/video is compressed, which can take a few seconds depending on what it is.
This is the code I have:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:^(void){
NSLog(#"Test");
}];
}
It dismisses the modal view controller, but doesn't call the completion argument. Am i doing something wrong?
void completion handlers are filled with a simple ^{, I've never seen your syntax before....
[picker dismissViewControllerAnimated:YES completion:^{
NSLog(#"Test");
}];
The only possible explanation I can come up with is that your image picker is being dismissed by some other means, and that you are not it's delegate (therefore you would not receive the didFinishPickingMediaWithInfo message). Another possibility could be a failure within the SDK at the time. I know from running a quick example project, that the completion block fires as expected in both syntactical models.
I have a UITableViewController that pops up a UIImagePickerController, user takes a pic, hits the Use button, Picker dismisses to show a custom thumbnail spinner while the image is being processed, then the spinner is replaced by the actual thumbnail at the end of processing.
At least that's how it worked in iOS4. Now with iOS5 it just sits there processing until it's finished, and then everything works correctly. But I want that spinner in there so the user knows something's happening, otherwise it looks like it just hung.
So I have this:
- (void) actionSheet: (UIActionSheet *)actionSheet didDismissWithButtonIndex (NSInteger)buttonIndex {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
// yada, yada, yada
[self presentModalViewController:picker animated:YES];
[picker release];
}
And then this gets called when the user picks "Use":
- (void) imagePickerController: (UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[self dismissModalViewControllerAnimated:YES];
[self performSelectorOnMainThread:#selector(processImage:) withObject:info waitUntilDone:NO];
animate = true;
}
And then this gets called to perform the processing while the thumbnail is spinning:
- (void) processImage:(NSDictionary *)info
{
UIImage *image = nil;
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
// processing of image
animate = false;
[activityImageView stopAnimating];
[activityImageView release];
[self.tableView reloadData];
}
Like I said, it worked perfectly with iOS4, but with iOS5, no such luck. So what's the deal? The image picker gets dismissed eventually, so why doesn't it get dismissed immediately?
I'm not sure why there's a disparity between iOS4 & iOS5 on this point. But your description of the UI hanging is fairly consistent with the code you've shown. The perform selector on main thread is doing just that, performing the selector on the main thread, which is the thread you're calling from. Because of this setting waitUntilDone: to NO is meaningless since it's not being sent to another thread it's simply running in order. You would probably get the results you want just from swapping the order, like So:
[self dismissModalViewControllerAnimated:YES];
animate = true;
[self performSelectorOnMainThread:#selector(processImage:) withObject:info waitUntilDone:NO];
But please note that this would be risky at best, since I assume // processing of image contains no concurrency. I prefer blocks for concurrency. And on top of that I like nested blocks to make the concurrency easy to follow, for example:
-(void)doSomeStuffInBackground{
// Prepare for background stuff
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// Do background stuff
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI from results of background stuff
});
});
}
So with that in mind, I would suggest something more like this:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[self dismissModalViewControllerAnimated:YES];
[self processImage:info];
}
-(void)processImage:(NSDictionary *)info{
animate = true;
UIImage *image = nil;
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// processing of image here on background thread
dispatch_async(dispatch_get_main_queue(), ^{
// update UI here on main thread
animate = false;
[activityImageView stopAnimating];
[activityImageView release];
[self.tableView reloadData];
});
});
}
This would offload the main work to a background thread to let the UI stay responsive.
Try to use
[[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
instead of:
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
i am using UIImagepickerController to take pictures from camera..i am using my own view over the camera view by using the cameraoverlayview property...i want to take a picture from camera when user clicks on a button in my custom view...i am using the following code
- (void)viewDidLoad {
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:imagePickerController animated:YES];
imagePickerController.showsCameraControls=NO;
imagePickerController.cameraOverlayView = self.customView;
}
- (IBAction) takePicture
{
[imagePickerController takePicture];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
imageView.image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[picker dismissModalViewControllerAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissModalViewControllerAnimated:YES];
}
but when i run this code it gives me error
ERROR: FigCreateCGImageFromJPEG returned -12905. Input (null) was 773625 bytes.
and i also get warnings for memory use level 2 and then level 1
and no image is displayed in the imageView.. can anyone help me what i might be doing wrong??
btw i am using iPhone 3G with iOS4.1 installed on it
UIImagePickerControllerOriginalImage is a symbol (an NSString * constant) and you can't assume its value. Use as is, without quotes. Other than that, if you properly retain and create both the picker and the image view, it should work.