I have an app that is continuously taking in images from the video buffer (using the process described here: http://www.benjaminloulier.com/articles/ios4-and-direct-access-to-the-camera) and performing various processing on the most recent image in the buffer. For my particular application, when something noteworthy is found in the image, I want to display this information to the user and have the user decide whether the information is correct or not.
I want to display 2 UIButtons on the screen when this information is returned and it is at this point that I wish the code to "pause" (like a runtime breakpoint) and wait to see which button the user clicks before resuming. After clicking a button, the buttons will disappear.
The reason for this is I can't have the camera continue to acquire images and process them while I am waiting for the user input.
Thanks!
EDIT:
Here is what my code basically looks like:
if (continueRunningScript == YES) {
NSString *results = [self processImage];
[self displayResults: results];
// Show pause button
dispatch_async(dispatch_get_main_queue(), ^{
[pauseButton setHidden: NO];
});
}
and the pause button code:
- (UIAction) pauseButtonPress:(id) sender {
[pauseButton setHidden: YES];
[playButton setHidden: NO];
continueRunningScript = NO;
}
and the play button code:
- (UIAction) playButtonPress:(id) sender {
[playButton setHidden:YES];
continueRunningScript = YES;
}
Where could I add more boolean to handle the delay?
Related
I start -play with AVAudioPlayer, and then set the nowPlaying dictionary like this:
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imagedNamed:#"AlbumArt"]];
[songInfo setObject:#"Audio Title" forKey:MPMediaItemPropertyTitle];
[songInfo setObject:#"Audio Author" forKey:MPMediaItemPropertyArtist];
[songInfo setObject:#"Audio Album" forKey:MPMediaItemPropertyAlbumTitle];
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
The lock screen always shows a pause button. I receive the remote control events correctly and I can toggle play/pause through the remote control events, but the lock screen keeps showing "pause" even when it is playing.
Now I seen this work with MPMoviePlayerController. Can someone explain how does the MPNowPlayingInfoCenter determine if it should show a play or a pause button?
Have you set the correct AVAudioSessionCategory on the AudioSession? it needs to be AVAudioSessionCategoryPlayback I believe to get it to work.
I'm not using MPNowPlaying at the moment, but apparently I have to, in order to get the audio info displayed on the lock screen.
However, in addition to what #user3061915 said, to manage the play/pause button, I've used UIEventTypeRemoteControl and it works perfect for controlling the play/pause button:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl)
{
if (event.subtype == UIEventSubtypeRemoteControlPlay)
{
[self playAudio];
}
else if (event.subtype == UIEventSubtypeRemoteControlPause)
{
[self pauseAudio];
}
else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause)
{
[self togglePlayPause]; //This method will handle the toggling.
}
}
I just fixed a problem like this in my own app. I originally used [[AVAudioSession sharedInstance] setCategory:withOptions:error:] and supplied AVAudioSessionCategoryOptionMixWithOthers and AVAudioSessionCategoryOptionDuckOthers. This turned out to be my problem. If you set mix with others, you get no remote control events. They still go to the iPod app. If you set duck others, you get remote control events, but it appears as though it causes the problem you describe: the play/pause button shows the wrong thing. I'm not sure why. I got the play/pause button to behave by setting options to 0, or actually just calling setCategory:error:.
When a UIButton is triggered, a UIActivityIndicator is started, and then stopped when implementLogin finishes:
-(IBAction)loginButton {
NSLog(#"loginButton triggered");
// Checks the Fields are not empty
if ([sessionIdField.text length] != 0 && [usernameField.text length] != 0 ) {
NSLog(#"Beginning Spinner");
// Displays spinner
[activitySpinner startAnimating];
[self implementLogin];
// Displays spinner
[activitySpinner stopAnimating];
}
}
However at runtime, the spinner doesn't appear! I have set the spinner to 'hide when stopped'.
When I set the activity indicator to animate before the view loads, it appears as it should, so I'm guessing it has a problem with the UIButton... (Also, I'm using 'Touch Up Inside' for the button.)
It's a simple problem... Can anyone help?
Thanks
Whatever implementLogin is doing (making a network request, perhaps?), it's doing it on the main thread, which is likely blocking UI updates like spinner animation.
You could recode something like this:
[activitySpinner startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT, 0), ^{
[self implementLogin];
dispatch_async(dispatch_get_main_queue(), ^{
// Stops spinner
[activitySpinner stopAnimating];
}
}
[Code is untested, but you get the idea.]
What is happening here is that you are dispatching the login task to the background, and the last thing that block will do is stop the spinner on the main thread (as a separate task).
Without more code, one can only guess the reason why it doesn't work.
I assume 'Beginning Spinner' output correctly(?)
If so, you probably didn't properly initialize the UIActivityIndicatorView.
Does it look like this?
activitySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activitySpinner.hidesWhenStopped = YES;
[view addSubview:activitySpinner];
I have a MenuViewController that loads when the app loads up; it is the root view of a UINavigationController.
Within the view I have a UIButton with an image that loads from a URL, as well as a label (its a picture indicating the weather and the current temp.).
Everything works fine, but if I am using the app on an iPhone 4, with multi-tasking, when the home button is pressed and then the app is reopened, I need the UIButton image and temp. label to reload.
I have tried calling this in my AppDelegate under applicationDidBecomeActive:
[self parseWeatherXML]; //re-parse weather data
[menuViewController reloadWeatherData]; //loads the image/label from the XML
with no luck.
I have also tried releasing menuViewController in applicationWillResign, then reallocating menuViewController in applicationDidBecomeActive so the viewDidLoad method gets called again, both ways just end up crashing my app.
Any help appreciated!
EDIT
Heres my method that gets called with the notification:
- (void)reloadWeather
{
[self parseWeatherXML];
UIImage *img = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString:iconURL]]];
if (img != nil)
{
NSLog(#"setting image");
[weatherButton setImage:img forState:normal];
img = nil;
}
currentTemp = [currentTemp stringByAppendingString:#"°F"];
[tempLabel setText:currentTemp];
tempLabel.adjustsFontSizeToFitWidth = YES;
if([self isIPad])
{
tempLabel.textAlignment = UITextAlignmentRight;
[tempLabel setFont: [UIFont systemFontOfSize: 45.0]];
}
currentTemp = nil;
}
I would have your MenuViewController become an observer to the UIApplicationDidBecomeActiveNotification and perform the parseWeatherXML data. I would think you would be refreshing the data from the URL, so you would need to wait for that data to come back again. So, I would follow the same logic that you are doing when you receive that notification.
UIApplicationDidBecomeActiveNotification
Posted when the application becomes
active. An application is active when
it is receiving events. An active
application can be said to have focus.
It gains focus after being launched,
loses focus when an overlay window
pops up or when the device is locked,
and gains focus when the device is
unlocked.
Availability
Available in iOS 2.0 and later.
Declared In
UIApplication.h
Have you tried saving the image and temp using a plist or something, during the applicationWillResign, and then during applicationDidBecomeActive, you can reload the image and temp from the saved file/label. Just another option to explore.
In my iPhone app, I want to add activity indicator on top of a searchbar.
When it is searching it should display activity indicator.
I have added the activity indicator in XIB and created its outlet.
I am making it hide when the searching finishes, but Activity Indicator does not display.
Problem
I figured out that search function(say A)(where I animate the activity indicator) in turn calls another function(say B) so the main thread is being used in executing the function B. But for activity indicator to animate we require the main thread.
So I tried calling function B using performSelectorInBackGround:withObject method. Now when I click search the activity indicator is shown but the functionality of function B does not execute.
What can be a work-around for this?
There is not quite enough in your question to go on, but to start debugging, I would do the following.
Verify that the activity variably is really wired to the UIActivityIndicator you are creating in IB. (I would set a breakpoint on the setHidden: lines and make sure the variable is not null. Or throw an NSAssert(activity,#"Whoops! actity is null"); in there.)
If the variable is indeed set, I would start checking that it is in the right place in the view hierarchy. (I'd try doing a [self.view addSubview:activity] and see that it appears. You might have to replace it somewhere else.)
You might also want to try having it on by default in IB, until you have everything figured out.
Good Luck. Hope this helps.
Save yourself the hassle of creating a custom activity indicator and use the standard one that's available for you already - in the top bar. Also, IMO users tend to expect that one to spin when something is happening.
UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;
Obviously, set it to NO when your activity is over.
First of all, make sure you have #synthesize activity at the top of your .m file. Then in the viewDidLoad method, type activity.hidesWhenStopped = TRUE;. Next, in the method that is called when the search starts, type [activity startAnimating]; and [activity stopAnimating]; in the method when the searching stops.
try this:
set hidesWhenStopped = NO, so that is displayed all the time and then hide and show it manually. But the View should be set in IB to hidden first.
- (void)startActivityView {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
activity_view.hidden = NO;
[pool drain];
}
- (void)stopActivityView {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
activity_view.hidden = YES;
[pool drain];
}
- (void)doSomething {
[self performSelectorInBackground:#selector(startActivityView) withObject:nil];
// do some time consuming work
[self performSelectorInBackground:#selector(stopActivityView) withObject:nil];
}
Perhaps you have a view in front of your activity indicator? What if you always bring it to the front....
loadView = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
loadView.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
loadView.center = window.center;
loadView.opaque = NO;
[window addSubview: loadView];
[window bringSubviewToFront:loadView];
[loadView startAnimating];
I suggest that you use DSActivityView for showing your activity indicator. The source code can be found at Dejal blog.
Showing, and hiding, the activity view is a simple line of code.
[DSActivityView activityViewForView:self.view];
start animating the activity indicator and with a delay of 0.1 or 0.2 just call the other method u want.... i tried and it is working for me....
I have got the solution and it is as follows.
I just wrote the below line in Search button click event.
[NSThread detachNewThreadSelector:#selector(threadStartAnimating:) toTarget:self withObject:nil];
And defined the function threadStartAnimating: as follows:
-(void)threadStartAnimating:(id)data
{
[activityIndicator setHidden:NO];
[activityIndicator startAnimating];
}
There is a text field to enter PIN in my login form. When i press "login" button i call the following method:
* (IBAction) loginBeforeAction:(id) sender {
[pin resignFirstResponder];
[progressView performSelectorInBackground:#selector(startAnimating) withObject:nil];
[self login];
}
but i the number pad is not hiding before the control moves to login method. In effect, i am can see the progress view with the number pad up. Is there any way to hide the number pad first and then show progress view ? plz help
Yes, The UI won't update until you get through the runloop. Meaning, your UI doesn't update until your login method finishes. Also, no need to update your progressView in the background either.
So, just delay the calls:
[progressView performSelector:#selector(startAnimating) withObject:nil afterDelay:0.1];
[self performSelector:#selector(login) withObject:nil afterDelay:0.25];