What is the recommended approach for starting a countdown NSTimer on one view and having it be accessible to stop interactively or to have run out in another?
I know one option is to have the NSTimer never turn off once kicked off and just use a global variable to determine whether to countdown or not but that seems inefficient.
More details of what I'm trying do:
In the main view I have a label that will update with the count down 00:00:00 and a button that I want to open a countdown UIDatePicker.
The second view with the UIDatePicker also has a start and stop button that will kick off or stop the countdown.
This view will close and the label on the original screen will display the countdown based on what the user selected previously.
It seems the timer you needed is independent from any of the views. You can use a singleton instance which will init once then be accessed anywhere. It's kind of like a global variable you mention above but if you have more than two views that need access to the timer singleton might be the most suitable choose
Related
Imagine in my app I have a label representing a virtual time and I want to change this label and update the time but this time is not system time and I want to be able to change it with different speeds (like every one real second is one or two minutes in this virtual time) and I also want to be able to call some functions at specific times.
I use UIKit.
How can I do this?
You will find that UIKit has UILabel. UILabel is a pretty straightforward thing to use. You can create it programmatically and position it, or use Interface Builder to create it as part of your View Controller's layout.
Either way, to update it, simply set the text property.
You can use NSTimer to update the text with a time and scale it using some sort of multiplier. Time calculations get tricky, so you may need to open a different question with more specifics about your time update.
Use the scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: method to have it call a method on your object, then [NSTimer invalidate]; to cancel it.
In my current project I've created an app that utilizes the position of the UISlider in relation to a target value displayed to the user. I've got full functionality however I'm now trying to spice it up a bit.
Is it possible to set the UISlider to move from (minimum through maximum) than (maximum through minimum) back and forth on its own when the user enters the app rather than having them drag it?
Thoughts:
Possibly use a looping sequence?
Not looking for someone to code this for me I quite enjoy that part. Just looking for guidance.
Further to the NSTimer answer, I wouldn't suggest using that, but CADisplayLink instead. Similar process, but instead of using NSTimer use CADisplayLink.
CADisplayLink synchronises with the screen refresh rate, so you can adjust the animation and slider value based on current frame, so the animation appears smooth.
http://patzearfoss.com/2011/09/02/more-cadisplaylink/
I think that in this case you would have to setup an NSTimer with a time that you wish per frame, separate out the action code within the slider into a routine that can be called by you, then within the timer action code, call your routine, and then set the slider position manually.
Look here for setting up an NSTimer
How do I use NSTimer?
The NSTimer will essentially allow you to setup any framerate you wish, AND keep it off of the MAIN thread.
UISlider has this method that allows you to programatically change the slider's value:
- (void)setValue:(float)value animated:(BOOL)animated
Be careful about using loops though, you don't want to block your main thread an make your app unresponsive.
Trumpetlick's answer provides good information on using an NSTimer, which should help you with this.
In my iOS application, when the user pushes a button in a view, a NSTimer is trigered in the controller.
On the third tick, I would like to make the background of the view bliking.
I've written the blinking function in the view (it should't be written in the controller, should it ?)
I can trigger this blinking function in the controller by
LostView *lostView = (LostView* ) self.view;
[lostView blinkBackground];
But it's bad, isn't it ? The controller shoudn't know the view neither the name of the function ?
I would like to apply the MVC pattern
Is the observer/obervable pattern applicable in this situation ?
Thanks
No it's not bad at all. It looks like you implemented the method to make the view blink in the view itself. That's fine, because it's directly related to the visual representation (i.e. the view part of MVC). You could reuse that view in any other app that requires a blinking view.
Since that blinking is triggered by an NSTimer I assume that it's somehow dependent on the logic in this specific app. The view can't (shouldn't) know when it's supposed to blink (that would only be the case if that blinking was a direct reaction of an interaction with it or another related part of the UI - or it was part of a more complex element, for example a countdown timer that always starts to blink when it reaches the last 10 secs or so. For example the UIButton provides the possibility to highlight it self if it's touched.)
But if that blinking is a reaction of some state transition in your app, maybe some new data becomes available or a countdown is about to expire, the controller is a perfectly reasonable place to trigger that.
My ActivityIndicator comes up at the right time but the user can still press the buttons on the view while processing is occurring. The reason I'm using ActivityIndicator is to prevent such usage.
How do I make sure that during the animation of ActivityIndicator, no UI interaction is possible?
Also, I would prefer that the current view is still displayed to the user(as in I wouldn't prefer having an opaque view of UIActivityIndicator-if that's possible-unless that's the only option)
Check out DSActivityView. It's a one-shot singleton that puts up a modal activity view VERY easily.
Include it in a View Controller, and then before you fire a long-running background process, you go:
[DSBezelActivityView activityViewForView:self.view];
And then when you're done and want to retire it, you go:
[DSBezelActivityView removeViewAnimated:YES];
Lots of configuration options, including the ability to put custom messages in the activity view... It's a great little library that I use ALL the time.
ActivityIndicator's job is to like names says indicate that something goes on, and not to disable all interactions...You should be the one to do that...you could try with setting userInteractionEnabled property to NO.
When everything is finished set it back to YES
I have always been a bit unclear on the type of tasks that should be assigned to viewDidLoad vs. viewWillAppear: in a UIViewController subclass.
e.g. I am doing an app where I have a UIViewController subclass hitting a server, getting data, feeding it to a view and then displaying that view. What are the pros and cons of doing this in viewDidLoad vs. viewWillAppear?
viewDidLoad is things you have to do once. viewWillAppear gets called every time the view appears. You should do things that you only have to do once in viewDidLoad - like setting your UILabel texts. However, you may want to modify a specific part of the view every time the user gets to view it, e.g. the iPod application scrolls the lyrics back to the top every time you go to the "Now Playing" view.
However, when you are loading things from a server, you also have to think about latency. If you pack all of your network communication into viewDidLoad or viewWillAppear, they will be executed before the user gets to see the view - possibly resulting a short freeze of your app. It may be good idea to first show the user an unpopulated view with an activity indicator of some sort. When you are done with your networking, which may take a second or two (or may even fail - who knows?), you can populate the view with your data. Good examples on how this could be done can be seen in various twitter clients. For example, when you view the author detail page in Twitterrific, the view only says "Loading..." until the network queries have completed.
It's important to note that using viewDidLoad for positioning is a bit risky and should be avoided since the bounds are not set. this may cause unexpected results (I had a variety of issues...)
This post describes quite well the different methods and what happens in each of them.
currently for one-time init and positioning I'm thinking of using viewDidAppear with a flag, if anyone has any other recommendation please let me know.
Initially used only ViewDidLoad with tableView. On testing with loss of Wifi, by setting device to airplane mode, realized that the table did not refresh with return of Wifi. In fact, there appears to be no way to refresh tableView on the device even by hitting the home button with background mode set to YES in -Info.plist.
My solution:
-(void) viewWillAppear: (BOOL) animated { [self.tableView reloadData];}
Depends, Do you need the data to be loaded each time you open the view? or only once?
Red : They don't require to change every time. Once they are loaded they stay as how they were.
Purple: They need to change over time or after you load each time. You don't want to see the same 3 suggested users to follow, it needs to be reloaded every time you come back to the screen. Their photos may get updated... you don't want to see a photo from 5 years ago...
viewDidLoad: Whatever processing you have that needs to be done once.
viewWilLAppear: Whatever processing that needs to change every time the page is loaded.
Labels, icons, button titles or most dataInputedByDeveloper usually don't change.
Names, photos, links, button status, lists (input Arrays for your tableViews or collectionView) or most dataInputedByUser usually do change.