I am trying to increase a variable's value while uibutton is kept pressing. But when user leaves button, increasing of variable's value will be stopped.
i have tried using threads with touch down and touchupinside but couldn't make it work.
-(void) changeValueOfDepthFields:(UIButton *)sender {
if (pressing)
pressing = NO;
else
pressing = YES;
pressingTag = 0;
while (pressing) {
[NSThread detachNewThreadSelector:#selector(increaseValue) toTarget:self withObject:nil];
}
}
- (void) stopValueChange:(UIButton *)sender {
pressing = NO;
}
[fStopUp addTarget:self action:#selector(changeValueOfDepthFields:) forControlEvents:UIControlEventTouchDown];
[fStopUp addTarget:self action:#selector(stopValueChange:) forControlEvents:UIControlEventTouchUpInside];
- (void) increaseValue {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
fstopVal = fstopVal + 0.1;
[self performSelectorOnMainThread:#selector(changeTextOfValues) withObject:nil waitUntilDone:YES];
[pool release];
}
- (void) changeTextOfValues {
fStopField.text = [NSString stringWithFormat:#"%.02f", fstopVal];
}
I wonder if there is an alternative way to do this or not. It seems very simple but couldn't think of any other solution than this one.
It is much easier to use an NSTimer.
- (void)changeValueOfDepthFields:(UIButton *)sender
{
if (!self.timer) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(increaseValue) userInfo:nil repeats:YES];
}
}
- (void)stopValueChange:(UIButton *)sender
{
if (self.timer) {
[self.timer invalidate];
self.timer = nil;
}
}
- (void)increaseValue
{
fstopVal = fstopVal + 0.1;
fStopField.text = [NSString stringWithFormat:#"%.02f", fstopVal];
}
Note: The previous code is just for reference, I didn't do any memory management for example.
Related
** I show count down timer on cell when i long press on cell.but the problem is that when i click on row timer started but suddenly when i click on second cell timer stop of previous cell and start timer new cell which i click ,but the main functionality which i need is that i have to show running previous timer and current timer . please any one give me right way for that.**
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{ AppDelegate *app=(AppDelegate *)[UIApplication sharedApplication].delegate;
CGPoint p = [gestureRecognizer locationInView:ChatTable];
NSIndexPath *indexPath = [ChatTable indexPathForRowAtPoint:p];
if ([[[userArray valueForKey:#"sender_id"] objectAtIndex:indexPath.row]isEqualToString: app.userId]) {
}
else{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
if ([imageCache objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]]==NULL) {
}
else
{
self.picId=[[userArray valueForKey:#"pic_id"] objectAtIndex:indexPath.row];
self.imageName=[[userArray valueForKey:#"imagename"] objectAtIndex:indexPath.row];
ChatTable.userInteractionEnabled=NO;
// self.navigationController.navigationBarHidden=YES;
image=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
self.pickerValue=[[userArray valueForKey:#"seconds"] objectAtIndex:indexPath.row];
image.image=[imageCache objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]];
[self.view addSubview:image];
[self showTableTime:indexPath];
}
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
UITableViewCell * myCell = [ChatTable cellForRowAtIndexPath:indexpathForTimer];
UILabel * myLabel = (UILabel *)[myCell viewWithTag:101];
myLabel.text=#"";
// self.navigationController.navigationBarHidden=NO;
[image removeFromSuperview];
}
}
}
-(void)showTableTime:(NSIndexPath *)indexPath
{
secondsLeft=[self.pickerValue integerValue];
indexpathForTimer=indexPath;
[self countDownTimer];
}
- (void)countDownTimer {
timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
- (void)updateCounter:(NSTimer *)theTimer {
UITableViewCell * myCell = [ChatTable cellForRowAtIndexPath:indexpathForTimer];
UILabel * myLabel = (UILabel *)[myCell viewWithTag:101];
if (secondsLeft >0) {
secondsLeft --;
UILabel * myLabel = (UILabel *)[myCell viewWithTag:101];
myLabel.text=[NSString stringWithFormat:#"0%d",secondsLeft];
}
else if(secondsLeft==0)
{
[self.image removeFromSuperview];
[timer invalidate];
ChatTable.userInteractionEnabled=YES;
myLabel.text=#"";
[self SendRequsetToServerOfSeenImage];
}
else
{
}
}
The problem is that you only store one timer/indexpath pair (you only use the variables "timer" and "indexPathForTimer"). As soon as you activate a second cell, the variable indexPathForTimer will be overwritten with the indexPath for the second cell, so you only update the second cell.
I would suggest you convert the variable timer into an NSMutableArray and indexPathForTimer into an NSMapTable and then do
// code to init the map table, perform this where you initialize your variables
// (you may want to use weakToStrong or weakToWeak depending on your memory
// management)
indexPathForTimer = [NSMapTable strongToStrongObjectsMapTable];
// use this code to create your timer instance with reference to the index path
// for which it was instantiated
NSTimer* newTimer = [NSTimer timerWithTimerInterval:1.0 target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
[timer addObject:newTimer];
[indexPathForTimer addObject:indexPath forKey:newTimer];
[NSRunLoop mainRunLoop] addTimer:newTimer forModes:NSRunLoopCommonModes];
In your updateCounter: method, you can then get the real index path like so
currentIndexPath = [indexPathForTimer objectForKey:theTimer];
Try this
- (void)countDownTimer
{
timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
}
I think you want to run multiple timer on view or on each cell. but it become complicated to handle multiple timers that running on different cells.
I want to start a timer when a viewWillAppear method gets called.
It's working perfectly, but I'm having a problem when I push a new view on this Current View, which already has a timer. When I pop that new View and recall viewWillAppear I want to start the timer again as before. I have most of the techniques but can't find a solution.
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[NSThread detachNewThreadSelector:#selector(createTimer) toTarget:self withObject:self];
}
- (void)createTimer
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
gameTimer = [[NSTimer timerWithTimeInterval:1.00 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES] retain];
[[NSRunLoop currentRunLoop] addTimer:gameTimer forMode:NSDefaultRunLoopMode];
timeCount = 360;
[runLoop run];
[pool release];
}
- (void)timerFired:(NSTimer *)timer
{
if(timeCount == 0)
{
[self timerExpired];
} else {
timeCount--;
if(timeCount == 0) {
[timer invalidate];
[self timerExpired];
}
}
timeLabel.text = [NSString stringWithFormat:#"%02d:%02d",timeCount/60, timeCount % 60];
}
- (void) timerExpired
{
//NSLog(#"Final == %#",arrayAnswers);
//NSLog(#"Attempt == %d",[arrayAnswers count]);
[gameTimer invalidate];
gameTimer = nil;
}
Well, based on experience, your problem is the timer's thread. Basically, the problem is here:
[NSThread detachNewThreadSelector:#selector(createTimer) toTarget:self withObject:self];
I'm not absolutely sure but I believe that your code is not really wrong. I haven't figured it out yet but I guess the NSTimer object is not being activated when detachNewThreadSelector: is used. Try executing the timer on the main thread.
[self performSelectorOnMainThread:#selector(createTimer) withObject:nil waitUntilDone:NO]
I've done this and got the results that I wanted.
I m struggling with this issue for so long but not able to find any solution for this
The issue i have is when i pause the audioplayer i want views to be paused from updating so i used timer invalidate to pause the views from loading but when i resume play only Audioplayer is resumed not the views cause i invalidated the timer.
Now i how i can resume updating views from that point where view was paused. By starting the timer again i can start updating views again but how program will know that at what view it was paused and it should resume updating views from that point. There are multiple views involved displayed code for only two.
-(void)playpauseAction:(id)sender
{
if
([audioPlayer isPlaying]){
[sender setImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[timer invalidate];
} else {
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11 target:self selector:#selector(displayviewsAction:) userInfo:nil repeats:NO];
}
}
- (void)displayviewsAction:(id)sender
FirstViewController *viewController = [[FirstViewController alloc] init];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
[viewController release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:23 target:self selector:#selector(secondViewController) userInfo:nil repeats:NO];
-(void)secondViewController {
SecondViewController *secondController = [[SecondViewController alloc] init];
secondController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:secondController.view];
[self.view addSubview:toolbar];
[secondController release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:27 target:self selector:#selector(ThirdviewController) userInfo:nil repeats:NO];
}
Thanks and appreciate for your answers and helping me out with this issue.
Use a background thread to basically bind the view to the player, something like this:
UIImageView* imageView; //the view that gets updated
int current_selected_image_index = 0;
float time_for_next_image = 0.0;
AVAudioPlayer* audioPlayer;
NSArray* image_times; //an array of float values representing each
//time when the view should update
NSArray* image_names; //an array of the image file names
-(void)update_view
{
UIImage* next_image_to_play = [image_names objectAtIndex:current_selected_image_index];
imageView.image = next_image_to_play;
}
-(void)bind_view_to_audioplayer
{
while(audioPlayer.isPlaying)
{
float currentPlayingTime = (float)audioPlayer.currentTime;
if(currentPlayingTime >= time_for_next_image)
{
current_selected_image_index++;
[self performSelectorOnMainThread:#selector(update_view) withObject:nil waitUntilDone:NO];
time_for_next_image = [image_times objectAtIndex:[current_selected_image_index+1)];
}
[NSThread sleep:0.2];
}
}
-(void)init_audio
{
current_selected_image_index = 0;
time_for_next_image = [image_times objectAtIndex:1];
}
-(void)play_audio
{
[audioPlayer play];
[self performSelectorInBackground:#selector(bind_view_to_audioplayer) withObject:nil];
}
-(void)pause_audio
{
[audioPlayer pause];
//that's all, the background thread exits because audioPlayer.isPlaying == NO
//the value of current_selected_image_index stays where it is, so [self play_audio] picks up
//where it left off.
}
also, add self as observer for the audioPlayerDidFinishPlaying:successfully: notification to reset when the audioplayer finishes playing.
I have this code in LongTapGestureRecognizer for autoscrolling a view:
-(void) longPressDetectedgesture:
(UILongPressGestureRecognizer*)recognizer
{
_btnautoscrollstop.hidden = NO;
_btnautoscroll.hidden = YES;
// if (autoscrollTimer == nil) {
autoscrollTimer = [NSTimer
scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
}
- (void)autoscrollTimerFired:(NSTimer*)timer {
CGPoint scrollPoint = self.table.contentOffset;
scrollPoint = CGPointMake(scrollPoint.x, scrollPoint.y + 1);
[self.table setContentOffset:scrollPoint animated:NO];
}
It works perfect for me, but my need is, the autoscrooling must stop when the user taps the screen for Longgesture for the second time and vise versa. How to stop this, when the user taps for a second time.
It looks like you're almost there. You probably want something like this:
if (recogniser.state == UIGestureRecognizerStateBegan) {
if (autoscrollTimer == nil) {
autoscrollTimer = [NSTimer scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
} else {
[autoscrollTimer invalidate];
autoscrollTimer = nil;
}
}
What i usually do is declare a global BOOL Alter; and initialize it Alter = NO; in viewDidLoad (or any other method) then
-(void) longPressDetectedgesture:(UILongPressGestureRecognizer*)recognizer
{
if(Alter)
{
Alter = NO;
[autoscrollTimer inValidate];
}
else
{
Alter = YES;
_btnautoscrollstop.hidden = NO;
_btnautoscroll.hidden = YES;
// if (autoscrollTimer == nil) {
autoscrollTimer = [NSTimer scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
}
}
create a BOOL called shouldFireTimer in viewDidLoad or similar and update it's value each time you detect a longpress
-(void) longPressDetectedgesture: (UILongPressGestureRecognizer*)recognizer {
_btnautoscrollstop.hidden = NO;
_btnautoscroll.hidden = YES;
if ( shouldFireTimer ) {
[autoscrollTimer invalidate];
autoscrollTimer = nil;
} else {
autoscrollTimer = [NSTimer
scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
}
shouldFireTimer = !shouldFireTimer;
}
- (void)autoscrollTimerFired:(NSTimer*)timer {
CGPoint scrollPoint = self.table.contentOffset;
scrollPoint = CGPointMake(scrollPoint.x, scrollPoint.y + 1);
[self.table setContentOffset:scrollPoint animated:NO];
}
or like Matt says above maybe just check nil status instead of using a BOOL. I suggest using a BOOL as you maybe firing autoscrollTimerFired in other circumstances too (from a button for example) i.e. it might not be nil when you want to call it.
I am having issue with invalidating a NSTimer.
I initialize a NSTimer with below function.
-(void) initLTTimer{
[self shutLTTimer];
[self setQuestion:questionCounter];
isQuestionAttempt=NO;
tmLeftTime=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateLeftTime:) userInfo:nil repeats:YES];
NSLog(#"Timer Initialized");
}
further I called a function updateLeftTime in its selector.
- (void)updateLeftTime:(NSTimer *)theTimer {
NSLog(#"%d",timeCounter);
timeCounter+=1;
tfLeftTime.text=[NSString stringWithFormat:#"%d", (QUESTION_TIME_LIMIT-timeCounter)];
if (timeCounter>=QUESTION_TIME_LIMIT) {
if (isQuestionAttempt==NO) {
[self increaseDropShots];
}
[self setQuestionBg];
timeCounter=0;
[self shutLTTimer];
[self updateQuestion:nil];
}
}
This function [self increaseDropShots]; called in above function.
here is the code of this function
-(void)increaseDropShots
{
NSString *imgName = #"DactiveRetake";
if (IS_IPAD) {
imgName = [imgName stringByAppendingString:#"_ipad"];
}
wrongAttemp+=1;
for (int i =1; i<=wrongAttemp; i++ )
{
UIImageView *img=(UIImageView *)[self.view viewWithTag:i+50];
[img setImage:[UIImage imageNamed:imgName]];
}
NSLog(#"Question dropped counter: %d",wrongAttemp);
if (wrongAttemp == 3)
{
[self shutLTTimer];
[CommonFunctions initGlobalVars];
[Bgplayer stop];
[Bgplayer release];
OverPageViewController *opvc=[[OverPageViewController alloc] initWithNibName:[CommonFunctions getXIBFile:#"OverPageViewController"] bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:opvc animated:YES];
[opvc release];
}
}
In this function I am killing this timer but I am unable.
-(void) shutLTTimer{
if ([tmLeftTime isValid]) {
[tmLeftTime invalidate];
tmLeftTime=nil;
}
}
This is the whole scenario of my application
Please help me what is the issue.
Answered after conversation in comments
Does the code definitely get to the line, [tmLeftTime invalidate];? You can check this by using a breakpoint or an NSLog.