NSTimer Stopwatch - xcode

I have a stopwatch that runs fine on my app however when I click on the back button to go to another view it stops. I want the stopwatch to keep running even when the user is viewing another page.
How do I accomplish this?
Ok added the code
code:
.h
UILabel *stopWatchLabel;
NSTimer *stopWatchTimer; // Store the timer that fires after a certain time
NSDate *startDate; // Stores the date of the click on the start button
#property (nonatomic, retain) IBOutlet UILabel *stopWatchLabel;
- (IBAction)onStartPressed:(id)sender;
- (IBAction)onStopPressed:(id)sender;
.m
- (void)viewDidUnload
{
[self setStopWatchLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss.SSS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
stopWatchLabel.text = timeString;
}
- (IBAction)onStartPressed:(id)sender {
startDate = [NSDate date];
// Create the stop watch timer that fires every 10 ms
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
}
- (IBAction)onStopPressed:(id)sender {
[stopWatchTimer invalidate];
stopWatchTimer = nil;
[self updateTimer];
}

Well it stops because you're releasing the view that it lives in when you pop it off the stack.
have you tried making a stopwatch class that handles the timer independent of the view?

The stopwatch stops because you're releasing the view that controls it.
You need to make sure that the NSTimer is not linked to any view.
Perhaps you can use subviews or Modal View Controllers (I think that may work) in order to not have the stopwatch released when the view is.
You could also try sending the stopwatch information to the next view through variables, and then having the other view take over the stopwatch from there.
There are most definitely other methods as well.
Either way, you need to make sure that the NSTimer is not released.

Exactly, if you look at your "ViewDidUnload" you're setting it to nil when the view gets released which it does when you go to another view.
Something you can try is to have a class that's running the timer and sending it over to the view that way it's still running even though the view that displays it is not in memory.
MVC style!

Yeah, what everyone else says.
On the ViewDidUnload it is releasing it. Meaning it is basically ending the operation as soon as that ViewController is exited.

I Dont know if the problem is already solved or not but still.
Create the Object of NSTimer in App Delegate Class and then instantiate the timer of in .m file of app delegate in this way your NSTimer will stay in memory. and when you want to stop or pause the timer you can just invalidate that object from any view Controller.

Related

NSTimer on UIToolbar

In my project I am implementing NSTimer to calculate time.
What I want to do is,
I am having my UIToolBar in my Timer.m file with tag 100.
and I want to add NSTimer on my UIToolBar from TimerController.m
But I am not able to add NStimer on UIToolBar.
My Timer is getting added over my navigation bar.
How to add my Timer on UIToolbar.
Can any one guide me.
Thanks in advance.
Here is my code...
Timer.m
UIToolbar* bottomToolbar = [[UIToolbar alloc] init];
bottomToolbar.frame = CGRectMake(0, 390, self.frame.size.width, 44);
[bottomToolbar sizeToFit];
bottomToolbar.tintColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
bottomToolbar.tag = 100;
[self addSubview:bottomToolbar];
and this is my time in TimerController.h
NSTimer* timer;
}
#property (nonatomic,retain) NSTimer* timer;
and code for this timer in TimerController.m
timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(displayTime) userInfo:nil repeats:YES];
and in displayTime method I will go for timing calculation.
I didn't found ant property to add timer over UIToolBar.
I tried using below code, but it give me warning with no output.
Warning as "incompatible pointer types sending NStimer* to prameter of UIView*"
UIToolbar *bottomBar = (UIToolbar*)[self.view viewWithTag:100];
[bottomBar addSubview:timer];
Here is the image how I want it....
#note :- I also checked whether my Toolbar tag is getting problem, but NO,
I am able to add UIToolbar and nslog tag correctly.
Thanks in advance

XCode View Controller Not Updating in Do Loop

I have a do loop that I want to execute a command every 1 second while a SWITCH is on.
The Code works fine ONCE, when I don't have the DO LOOP.
However, as soon as I add the LOOP, none of the labels in the view controller are updated, the back button for the storyboard doesn't work, and the SWITCH will not toggle off. Essentially, the DO LOOP keeps looping, but nothing on the screen will work, nor can I back out.
I know I'm doing it wrong. But, I don't now what. Any thoughts would be appreciated.
I attached the code that gets me in trouble.
Thanks,
- (IBAction)roaming:(id)sender {
UISwitch *roamingswitch = (UISwitch *)sender;
BOOL isOn = roamingswitch.isOn;
if (isOn) {
last=[NSDate date];
while (isOn)
{
current = [NSDate date];
interval = [current timeIntervalSinceDate:last];
if (interval>10) {
TheCommand.text=#"ON";
[self Combo:sendcommand];
last=current;
}
}
}
else
{
TheCommand.text=#"OFF";
}
}
iOS and OSX are event based systems and you cannot use loops like this in the main (UI) thread to do what you want to do, otherwise you don't allow the run loop to run and events stop being processed.
See: Mac App Programming Guide section "The App’s Main Event Loop Drives Interactions".
What you need to do is set-up a timer (NSTimer) which will fire every second:
.h file:
#interface MyClass : NSView // Or whatever the base class is
{
NSTimer *_timer;
}
#end
.m file:
#implementation MyClass
- (id)initWithFrame:(NSRect)frame // Or whatever the designated initializier is for your class
{
self = [super initInitWithFrame:frame];
if (self != nil)
{
_timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:YES];
}
return self;
}
- (void)dealloc
{
[_timer invalidate];
// If using MRR ONLY!
[super dealloc];
}
- (void)timerFired:(NSTimer*)timer
{
if (roamingswitch.isOn)
{
TheCommand.text=#"ON";
[self Combo:sendcommand];
}
}
#end
Give your processor enough time to update your view controller and not be interrupted by other processes. I give it 0.5 second before and after the view controller update signal.
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
self.CrashingTime.text = [NSString stringWithFormat: #"Crash Time = %f ms", outputOfCrashTime];
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];

How not to Release a View in Xcode

Hello I have a stopwatch view and when the user clicks on the back button to go to another view the stopwatch will stop. I had people tell me that is because it is being released.
I want the stop watch to keep running.
So how do I un-release or not allow it to be released?
Here i my code.
.h
UILabel *stopWatchLabel;
NSTimer *stopWatchTimer; // Store the timer that fires after a certain time
NSDate *startDate; // Stores the date of the click on the start button
#property (nonatomic, retain) IBOutlet UILabel *stopWatchLabel;
- (IBAction)onStartPressed:(id)sender;
- (IBAction)onStopPressed:(id)sender;
.m
- (void)viewDidUnload
{
[self setStopWatchLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss.SSS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
stopWatchLabel.text = timeString;
}
- (IBAction)onStartPressed:(id)sender {
startDate = [NSDate date];
// Create the stop watch timer that fires every 10 ms
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
}
- (IBAction)onStopPressed:(id)sender {
[stopWatchTimer invalidate];
stopWatchTimer = nil;
[self updateTimer];
}
I would try a different approach, than to change the view controller's behavior:
You can make the timer independent from the view controller by moving the timer functionality into a separate object. That way the timer object has a different life cycle than the view controller object. For example, you can create (and release) the timer object in the application delegate, and create a reference to it and access it in your view controller.

MPMoviePlayerController keeps playing after view did unload?

I have a detail view, and when viewdidload in detailviewcontroller, MPMoviePlayerController allocs and plays an audio, but even if I navigate backto main table, audio is still being played.
How can I stop MPMovieplayercontroller when I navigate back to main table ? This is my MPMoviePlayerController code:
.h
MPMoviePlayerController *player;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
//Get the Movie
NSURL *movieURL = [NSURL URLWithString:#"some link"];
player = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
//Place it in subview, else it won’t work
player.view.frame = CGRectMake(20, 20, 280, 25);
player.backgroundView.backgroundColor = [UIColor clearColor];
[self.view addSubview:player.view];
// Play the movie.
[player play];
}
I even added following code into viewdidunload method, but didn't work.
- (void)viewDidUnload {
[player stop];
player.initialPlaybackTime = -1;
[player release];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
What do you guys suggest ?
Thanks in advance,
I liked the user experience of viewDidDisappear better than viewWillDisappear. The animation starts and the movie stops after - the audio flows better for me this way.
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_moviePlayer stop];
}
I am having a similar issue. I am unable to use "viewDidDisappear" or "viewWillDisappear" because I have a "config" type view that can be opened while the content is playing, and it will trigger those two methods.
EDIT: Found that viewDidUnload and viewWillUnload are not getting called any more (I'm currently on an iOS 6+ device)...
From the documentation:
Availability: iOS (3.0 and later) Deprecated: Views are no longer
purged under low-memory conditions and so this method is never called.
I just created a simple function called unload, and inside the function, set any objects I needed to = nil (I'm using ARC). At the time that I make the call to remove the view, I call the unload function as well. Hope it helps someone.

IOS: use navigation controller in a subview

In a view of my program I have a button and with this button I open a subview; this subview is a view with a tableview. I want go to another view when I push a row of the tableview so I want to make this with a navigation controller; how can I do this?
Your table view delegate will receive a tableView:didSelectRowAtIndexPath: message when you click on one of the table's rows.
You can put there your code to create the UINavigationController and push on to it your new view.
This sample code (from another answer of mine on S.O.) shows how you can do that:
UINavigationController* navigation = [[UINavigationController alloc] init];
iVkViewController *overviewViewController = [[iVkViewController alloc] init];
overviewViewController.title = #"First";
[navigation pushViewController:overviewViewController animated:NO];
This should help you getting things on track.
One side note: you might think of having a navigation controller from the very start, this would make your UI more "well-behaved", but this depends ultimately on your app requirements.
If UIViewController addSubView a view of UITableViewController,you want to push in the method of tableView:didSelectRowAtIndexPath,you should check if self.navigationController is nil. If it's nil,You probably should use
[self.parentViewController.navigationController pushViewController:controller animated:YES];
if self.parentViewController is also nil,Sometimes,you have to set a #property to point out the parentViewController In UITableViewController,like:
#property (nonatomic, weak) UIViewController *parentVC;
and in UIViewController:
UITableViewController *tableViewVC = [[UITableViewController alloc] init];
tableViewVC.parentVC = self;
In UITableViewController ,-tableView:didSelectRowAtIndexPath:
[self.parentVC.navigationController pushViewController:controller animated:YES];

Resources