How do i set up a button (IBAction and UIButton attached) to continue to run the IBAction or a function while the button is being pressed, running a functioning continuously until the button is let up.
Should i attach a value changed receiver?
Simple question, but I can't find the answer.
[myButton addTarget:self action:#selector(buttonIsDown) forControlEvents:UIControlEventTouchDown];
[myButton addTarget:self action:#selector(buttonWasReleased) forControlEvents:UIControlEventTouchUpInside];
- (void)buttonIsDown
{
//myTimer should be declared in your header file so it can be used in both of these actions.
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(myRepeatingAction) userInfo:nil repeats:YES];
}
- (void)buttonWasReleased
{
[myTimer invalidate];
myTimer = nil;
}
Add a dispatch source iVar to your controller...
dispatch_source_t _timer;
Then, in your touchDown action, create the timer that fires every so many seconds. You will do your repeating work in there.
If all your work happens in UI, then set queue to be
dispatch_queue_t queue = dispatch_get_main_queue();
and then the timer will run on the main thread.
- (IBAction)touchDown:(id)sender {
if (!_timer) {
dispatch_queue_t queue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// This is the number of seconds between each firing of the timer
float timeoutInSeconds = 0.25;
dispatch_source_set_timer(
_timer,
dispatch_time(DISPATCH_TIME_NOW, timeoutInSeconds * NSEC_PER_SEC),
timeoutInSeconds * NSEC_PER_SEC,
0.10 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_timer, ^{
// ***** LOOK HERE *****
// This block will execute every time the timer fires.
// Do any non-UI related work here so as not to block the main thread
dispatch_async(dispatch_get_main_queue(), ^{
// Do UI work on main thread
NSLog(#"Look, Mom, I'm doing some work");
});
});
}
dispatch_resume(_timer);
}
Now, make sure to register for both touch-up-inside and touch-up-outside
- (IBAction)touchUp:(id)sender {
if (_timer) {
dispatch_suspend(_timer);
}
}
Make sure you destroy the timer
- (void)dealloc {
if (_timer) {
dispatch_source_cancel(_timer);
dispatch_release(_timer);
_timer = NULL;
}
}
UIButton should call a starting method with touchDown event and call ending method with touchUpInside event
Related
I am making a game with a boost button. Of course, just leaving it as enabled would allow the player to tap it constantly. So, I need a 20 second delay before it is possible to push the button again. Also, would it be possible to show this progression on the button, preferably on the button itself?
In the future please try to show what you have tried to solve your problem. However, since you are new I'm going to let it slide once!
This code uses a NSTimer that is called once per second. It will fire what ever code you specify for "Boost". It will also disable user interaction on your button until it has been 20 seconds from when the button was pressed at which point it will allow the user to press the button again, and finally, this code displays how many seconds remain until "Boost" can be used again on the titleLabel property of your button.
- (IBAction)buttonPressed:(id)sender
{
myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(activateBoost) userInfo:nil repeats:YES];
}
- (void)activateBoost
{
if (myButton.userInteractionEnabled == YES) {
//Put your Boost code here!
}
if ([myButton.titleLabel.text intValue] == 0) {
[myTimer invalidate];
[myButton setTitle:#"20" forState:UIControlStateNormal];
myButton.userInteractionEnabled = YES;
}else{
myButton.userInteractionEnabled = NO;
int currentTime = [myButton.titleLabel.text intValue];
int newTime = currentTime - 1;
myButton.titleLabel.text = [NSString stringWithFormat:#"%d",newTime];
}
}
In order for the above code to work, you will need the declare a NSTimer named "myTimer" and a UIButton "myButton". You will also need to set the buttons initial text to "20".
How do you create a time elapsed button in objective-c iphone SDK. To be a little more specific, this button will show in text how much time has elapsed since you've been holding the button. So for the time to elapse you must still have a finger on the button, not letting go. Once you let go the timer should restart. Note: For the iphone, not mac.
Use these two methods for buttons events. touchDown is called when you press the button and touchUp will be called when you lift your finger from the button. Calculate the time difference between these two methods. Also you can start timer in touchDown and stop/restart it in touchUp.
//connect this action with Touch up inside
- (IBAction)touchUp:(id)sender {
NSLog(#"up");
}
//connect this to tocuh down
- (IBAction)touchDown:(id)sender{
NSLog(#"down");
}
first, set an int variable at your header file
#property int timerCount;
#property (nonatomic, strong)NSTimer *yourTimer;
dont forget to synthesize it at the implementation file
(if you're still on lower SDK, you can change "strong" to "retain")
and then make the button and it's function
UIButton *yourButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
[yourButton setTag:1];
[yourButton setBackgroundColor:[UIColor redColor]];
[yourButton addTarget:self action:#selector(buttonHoldDown) forControlEvents:UIControlEventTouchDown];
[yourButton addTarget:self action:#selector(buttonRelease) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:yourButton];
this way, you've add a button at x:0 y:0 on your view with red color, containing two action target which is touch down and up inside
when you touch the button, the buttonHoldDown function is triggered, and when u release the button, the buttonRelease function is triggered
and then, fill the function
-(void)buttonHoldDown
{
yourTimer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(timerStart) userInfo:nil repeats:NO];
timerCount = 0;
}
-(void)buttonHoldUp
{
NSLog(#"the timer stops at %d seconds", timerCount);
timerCount = 0;
[yourTimer invalidate];
}
-(void)timerStart
{
timerCount++;
}
this way, when you touch the button, the program creates a timer and revalue the int timerCount to 0, which will be increased as the timer ticks in the "timerStart" function.
as you release the button, the function will track your current timerCount record and print it on the system, and then stop the timer
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Change the time interval of a Timer
So I have a timer:
timer=[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(createNewImage) userInfo:nil repeats:YES];
And I would like that the timer decrease every ten seconds, that scheduledTimerWithTimeInterval goes to 1.5 after ten seconds then to 1.0 after 10 seconds... Is it possible to do this, and if it is possible, how can I do it?
You can't modify a timer after you created it. To change the timer interval, invalidate the old timer and create a new one with the new interval.
You don't have to use several timers, all you have to do is add a variable to use for the time interval, then create a method that invalidates the timer, changes the variable and starts the timer again. For instance you could make a method that starts the timer.
int iTimerInterval = 2;
-(void) mTimerStart {
timer = [NSTimer scheduledTimerWithTimeInterval:iTimerInterval target:self selector:#selector(createNewImage) userInfo:nil repeats:YES];
}
-(void) mTimerStop {
[timer invalidate];
iTimerInterval = iTimerInterval + 5;
[self mTimerStart];
}
This would be the simple way to decrease the timer interval and keep the timer going, but I would personally prefer using the one below, because it makes sure that the timer has only ran once, that way it will not duplicate the instance, forcing your app to become glitchy and it also makes things easier for you.
int iTimerInterval = 2;
int iTimerIncrementAmount = 5;
int iTimerCount;
int iTimerChange = 10; //Variable to change the timer after the amount of time
bool bTimerRunning = FALSE;
-(void) mTimerToggle:(BOOL)bTimerShouldRun {
if (bTimerShouldRun == TRUE) {
if (bTimerRunning == FALSE) {
timer = [NSTimer scheduledTimerWithTimeInterval:iTimerInterval target:self selector:#selector(mCreateNewImage) userInfo:nil repeats:YES];
bTimerRunning = TRUE;
}
} else if (bTimerShouldRun == FALSE) {
if (bTimerRunning == TRUE) {
[timer invalidate];
bTimerRunning = FALSE;
}
}
}
-(void) mCreateNewImage {
//Your Code Goes Here
if (iTimerCount % iTimerChange == 0) { //10 Second Increments
iTimerInterval = iTimerInterval + iTimerIncrementAmount; //Increments by Variable's amount
[self mTimerToggle:FALSE]; //Stops Timer
[self mTimerToggle:TRUE]; //Starts Timer
}
iTimerCount ++;
}
-(void) mYourMethodThatStartsTimer {
[self mTimerToggle:TRUE];
}
I didn't finish all of the coding, but this is most of what you will need. Just change a few things and you'll be good to go!
You will need a set or sequence of timers, one for each different time interval. Stop/invalidate one timer and start the next timer when you want to change to the next time interval in your time sequence.
first of all thanks for getting into my questions.
now, i tried a lot of different ways to call some function in my code but the ways i find it works (performselector:withobject:afterdelay) are get into the function immediately and i need the function to make some "if's" after random times.
Well you can see the code in here-
-(void)playGame{
isButtonPressed=NO;
int minimum=1;
int maximum=4;
int randomTime=(arc4random()%(maximum-minimum))+minimum;
[self performSelector:#selector(ifButtonNotPressed) withObject:nil afterDelay:randomTime];
}
-(void)closingAction{
NSLog(#"Closing Panel automatic");
if (randomFrog==1){
[self performSelector:#selector(animatePanelCloseAction::) withObject:gameImage1_up withObject:gameImage1_down];
}
[self performSelector:#selector(playGame) withObject:nil afterDelay:0.25];
}
-(IBAction)buttonAction:(id)sender{
if (sender == gameButton1 && randomFrog==1){
[self performSelector:#selector(disableAllButtons)];
score=score+1;
isButtonPressed=YES;
[scoreLabel setText:[NSString stringWithFormat:#"Score:%d",score]];
[self performSelector:#selector(closingAction)];
}
}
-(void)ifButtonNotPressed{
if (isButtonPressed==NO){
[self performSelector:#selector(closingAction)];
}
}
as you can see, im trying to check if button was pressed, but its going inside and check it immeditlly and perform it after delay.
how can i call it after real delay ?!
thank you all.
amir.
Try NSTimer to fix this issue.
if(callTimer)
{
[callTimer invalidate];
callTimer=nil;
}
callTimer=[NSTimer scheduledTimerWithTimeInterval:0.50 target:self selector:#selector(callFunction) userInfo:nil repeats:NO];
with help of this you can call any function at particular time interval. if function call again then it invalidates current timer and create new timer for that.
Dont forgot to invalidate timer after calling function means invalidate timer in particular function.
Hey you can use NSTimer class for the same.
- (void)FireTimer : (NSInteger) afterTimeInterval
{
if (afterTimeInterval > 0) //afterTimeInterval is in seconds
{
[NSTimer scheduledTimerWithTimeInterval: afterTimeInterval
target: self
selector: #selector(ResetListAfterExpiration:)
userInfo: nil
repeats: NO];
}
}
- (void)ResetListAfterExpiration: (NSTimer *)timer
{
// your actions
… … …
[timer invalidate]; // must be done to prevent memory leak
}
//Now You call the FireTimer method from where ever you want and it will wait for afterTimeInterval seconds and call the method ResetListAfterExpiration. That's your answer.
Basically, I have an array of buttons I want to iterate and highlight (among other things) one after another, with a delay in-between. Seems like an easy task, but I can't seem to manage to get it to work cleanly while still being responsive.
I started out with this:
for MyButton *button in buttons {
[button highlight];
[button doStuff];
usleep(800000); // Wait 800 milliseconds.
}
But it is unresponsive, so I tried using the run loop instead.
void delayWithRunLoop(NSTimeInterval interval)
{
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:interval];
[[NSRunLoop currentRunLoop] runUntilDate:date];
}
for MyButton *button in buttons {
[button highlight];
[button doStuff];
delayWithRunLoop(0.8); // Wait 800 milliseconds.
}
However, it is also unresponsive.
Is there any reasonable way to do this? It seems cumbersome to use threads or NSTimers.
NSTimer will be perfect for this task.
The timer's action will fire ever x seconds, where x is what you specify.
The salient point is that this doesn't block the thread it runs on. As Peter said in the comments for this answer, I was incorrect in saying the timer waits on a separate thread. See the link in the comment for details.
Nevermind, Jasarien was right, NSTimer is perfectly suitable.
- (void)tapButtons:(NSArray *)buttons
{
const NSTimeInterval waitInterval = 0.5; // Wait 500 milliseconds between each button.
NSTimeInterval nextInterval = waitInterval;
for (MyButton *button in buttons) {
[NSTimer scheduledTimerWithTimeInterval:nextInterval
target:self
selector:#selector(tapButtonForTimer:)
userInfo:button
repeats:NO];
nextInterval += waitInterval;
}
}
- (void)tapButtonForTimer:(NSTimer *)timer
{
MyButton *button = [timer userInfo];
[button highlight];
[button doStuff];
}