Load UIImagePickerController in background - iphone

When my app starts I would like to initialize an UIImagePickerController. Since this can take several seconds, I would like to do it in the background. What is the best way to ensure that the background task finished, before invoking the picker?
Currently I have the following code. It works, but it will crash if one invokes the picker before the background task is done.
- (void) viewDidAppear: (BOOL)animated {
[super viewDidAppear: animated];
[self performSelectorInBackground:#selector(initPicker) withObject:nil];
....
}
and
- (void) initPicker {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"picker start... ");
[self setPicker: [[UIImagePickerController alloc] init]];
NSLog(#"picker done.");
[pool release];
}
Thank you!
Edit: It turns our this question is somewhat theoretical. Computing [[UIImagePickerController alloc] init] only takes time in debug mode on the device. So for production code, there is no need to run anything in the background. Also, [[UIImagePickerController alloc] init] seems to lock the main thread, so even in debug mode there is no advantage of placing it on a background thread.

Maybe a simple flag can do the job ?
#interface MyViewController : UIViewController
{
BOOL _pickerIsLoaded;
}
#end
#implementation MyViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
_pickerIsLoaded = NO;
[self performSelectorInBackground:#selector(initPicker) withObject:nil];
}
- (void)initPicker
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"picker start... ");
[self setPicker: [[UIImagePickerController alloc] init]];
NSLog(#"picker done.");
_pickerIsLoaded = YES;
[pool release];
}
#end

I would use NSConditionLock for signaling that your controller is loaded. In the -initPicker method I would set the condition when the UIImagePickerController is finish initializing. And in your IBAction for the showing the picker, I would check for that condition. For more options, see Threading Programming Guide.

Can you wait until your "picker done" and then add the picker view to whatever view makes it visible?
Something like this, right after your "picker done" statment:
[self presentModalViewController: theImagePickerController]; // assuming self is a viewController.

Related

Best way to use imagepickercontroller in iphone?

I am using UIImagePickerController to select the image from the PhotoLibrary in my application. I have used two different approaches for this. At first I have used a class variouble UIImagePicker with below code.
imagepicker = [[UIImagePickerController alloc]init];
imagepicker.delegate = self;
imagepicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagepicker.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:self.imagepicker animated:YES];
Above code is working fine.But when I clicked on the button it is taking some time to react with the animation in this case.Then I used the autorelease pool approach with this method
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
if([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary])
{
UIImagePickerController *picker= [[[UIImagePickerController alloc]init]autorelease];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:picker animated:YES];
}
[pool release];
Also works charm. Both of them showing no leak in the analyser.Can anybody point me the right approach.
Well, no much to say here... Both approaches work, both approaches are correct, use whichever you prefer.
One minor point: if you are regularly presenting the image picker, you better use the first method, and assign it to an instance variable (it isn't called a "class variable"!) only for the first time, and don't release it until - dealloc - this way, you save the continuous allocation-deallocation of the image picker every single time the user chooses an image.

Blinking UILabel Cocoa Touch

Is it possible to make a blinking UILabel in Cocoa Touch or do I need an UIview with Core Animation for that?
Take Martin's advice, and then have a look at NSTimer to handle the "blink" actions.
+ scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
All UIViews (including UILabel) has a hidden property which you can toggle on and off to make it "blink".
For fun, I decided to write this subclassing NSOperation.
Excerpt from BlinkingLabelOperation.m
- (void)main {
SEL update = #selector(updateLabel);
[self setThreadPriority:0.0];
while (![self isCancelled]) {
if (label_ == nil)
break;
[NSThread sleepForTimeInterval:interval_];
[self performSelectorOnMainThread:update withObject:nil waitUntilDone:YES];
}
}
- (void)updateLabel {
BlinkingColors *currentColors = nil;
if (mode_)
currentColors = blinkColors_;
else
currentColors = normalColors_;
[label_ setTextColor:currentColors.textColor];
[label_ setBackgroundColor:currentColors.backgroundColor];
mode_ = !mode_;
}
Sample view controller code:
- (void)viewDidLoad
{
[super viewDidLoad];
BlinkingColors *blinkColors = [[BlinkingColors alloc] initWithBackgroundColor:[UIColor whiteColor]
textColor:[UIColor redColor]];
BlinkingLabelOperation *blinkingOp = [[BlinkingLabelOperation alloc] initWithLabel:clickLabel freq:1.0 blinkColors:blinkColors];
// put the operation on a background thread
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[queue addOperation:blinkingOp];
[blinkColors release];
}
For a complete listing, you will find it here. Please leave comments and let me know what are your thoughts.

iphone, background thread not working properly

I want to display the view first and then load the data in a background thread. When I navigate from root controller to the view controller, I want to display the view first. As of now, it stays on the root controller until the view controller is loaded. Here's my code for the root controller.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ProductDetailViewController *tempProductDetail = [[ProductDetailViewController alloc] init];
[self.navigationController pushViewController:tempProductDetail animated:YES];
[tempProductDetail release];
}
ProductDetailViewController, here I want to display the view first and then load the data...
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
[self performSelectorOnMainThread:#selector(workerThread) withObject:nil waitUntilDone:NO];
}
-(void) workerThread{
NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
[arPool release];
}
Don't know what I'm doing wrong. Please, help.
Use [self performSelectorInBackground:#selector(workerThread) withObject:nil]; instead of
[self performSelectorOnMainThread:#selector(workerThread) withObject:nil waitUntilDone:NO];
found the answer for this issue,
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
[self performSelectorInBackground:#selector(workerThread) withObject:nil];
}
- (void) workerThread
{
// Set up a pool for the background task.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// only do data fetching here, in my case from a webservice.
//...
// Always update the components back on the main UI thread.
[self performSelectorOnMainThread:#selector(displayView) withObject:nil waitUntilDone:YES];
[pool release];
}
// Called once the background thread task has finished.
- (void) displayView
{
//here in this method load all the UI components
}
Consider using the following pattern instead for threading, in my opinion it's much cleaner:
- (void)viewWillAppear:(BOOL)animated
{
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(someFunction)
object:nil];
[[NSOperationQueue currentQueue] addObject:operation]; // this will actually start the thread
[operation release];
}
- (void)someFunction
{
// don't need to initialize and release an autorelease pool here,
// you can just write a function as usual ...
[self updateUI];
}
- (void)updateUI
{
if (![NSThread isMainThread]) // if we need a UI update, force it on main thread
{
[self performSelectorOnMainThread:#selector(updateUI) withObject:nil waitUntilDone:YES];
return;
}
// do UI updates here
}
By writing code in this way, you can more dynamically decide which function you want to thread, since there is no autorelease pool requirement. If you need to do UI updates, the updateUI function will make sure for itself that it's running on the main thread, so the caller doesn't need to take this into account.

Using UIImagePickerController in the game

I want to make a game, where the user can touch a picture of a TV and then choose a picture from their photo library.
I had success working with UITextFields, adding them to my EAGLView as subviews But I haven't been able to do the same thing with an UIImagePickerController , which seems the only way to do what I want to do.
Any help is appreciated !
UPDATE
With the suggestion of zpasternack I managed to make the menu appear by adding the UIImagePickerControllerDelegate, UINavigationControllerDelegate and using this method:
- (void) chooseImageFromLibrary {
if( ![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] ) return;
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePickerController.allowsEditing = YES;
[self addSubview:imagePickerController.view];
[imagePickerController viewWillAppear:YES];
[imagePickerController viewDidAppear:YES];
}
I call the chooseImageFromLibrary method at the start. It shows the interface, but as soon as i hit cancel or choose the app stops.
Can anyone suggest me:
1) How to make the cancel and choose buttons work.
2) How to call the UIImagePickerController whenever I want ( by calling chooseImageFromLibrary again ??).
3) When the user hits choose..Where do i find the UIImage the user just picked to ?, how do i pick it ?
Thanks.
I've never used one over an EAGLView, but UIImagePickerControllers are typically invoked with presentModalViewController, like:
- (void) chooseImageFromLibrary {
if( ![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] ) return;
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePickerController.allowsEditing = YES;
[self presentModalViewController:imagePickerController animated:YES];
}
Nervermind, problem solved. i just needed to overwrite some functions to make use of the UIImagePickerController.

iPhone: UIImagePickerController Randomly Fails to Take Picture

I use a UIPickerViewController to take picture. It works 80% but seemingly at random it fails to take a picture. In tracing the code I found out that it occasionally goes to
-PinRecordNewTableViewController:viewDidUnload.
That is where it fails because it set nil to all ivars.
#interface PinRecordNewTableViewController : UITableViewController {
}
...
#implementation PinRecordNewTableViewController
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
...
PinRecordNewPicture *pinRecordNewPicture = [[PinRecordNewPicture alloc] initWithNibName:#"PinRecordNewPicture" bundle:nil];
pinRecordNewPicture.delegate = self;
[self.navigationController pushViewController:pinRecordNewPicture animated:YES];
[pinRecordNewPicture release];
...
}
#interface PinRecordNewPicture : UIViewController
...
#implementation PinRecordNewPicture
...
- (void)picturePicker:(UIImagePickerControllerSourceType)theSource {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = theSource;
picker.allowsEditing = YES;
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (IBAction) takePicture:(id)sender {
UIImagePickerControllerSourceType source = UIImagePickerControllerSourceTypeCamera;
if ([UIImagePickerController isSourceTypeAvailable:source]) {
[self picturePicker:source];
}
What did I do wrong? Did I miss something that causes it to behave "randomly"?
Thanks in advance for your help.
If it called viewDidUnload, then it is very likely that your app is running out of memory. This could be a problem, or just the result of editing large images in phone.
If you're trying to take multiple pictures, save the current one to the Documents area of the app. It frees up the memory. This way, the memory warning can be avoided.
If ViewDidUnload is being called, you might think about saving the relevant state of the app in didReceiveMemoryWarning and restoring it in viewDidLoad. This is done using NSUserDefaults class