In my application i want to set inactivity timeout (IdleTime).
How can i set this?
Is there any way to monitor all events in myappdelegate?
For eg i have two UIViewController classes.
when i click one control in UIViewController1 or UIViewController2 it should be monitored by myappdelegate
To monitor all user interaction events in application you can use UIWindow subclass. Implement sendEvent: method in it:
- (void)sendEvent:(UIEvent*)event {
[super sendEvent:event];
// Process event or just reset inactivity time
}
To use it in your application you need to open application main xib (e.g. MainWindow.xib) and set custom type for UIWindow instance there.
I would probably build a singleton object to monitor it. Putting that functionality with a view or window is semantically muddy.
The class could be called "EventTracker" or something.
It's interface could be very simple:
-(int)secondsSinceLastActivity
-(void)resetActivityTimer
-(EventTracker *)instance
Anywhere in your app, you could call [EventTracker instance] to get the single object, and check time or reset the time.
This will allow for the most expandability down the line.
Related
Looking at the example in Beginning iOS 5 for persisting your application state, in the first viewController that is shown for the app, they register for applicationWillResignActive in viewDidLoad:. So that makes sense to me in that you register for that notification when your first view is shown.
I'm confused on whether you always do this, or where you typically register for this notification. Q1) Like do they register for this notification in this viewController so they can recreate this view? Q2) If so, do I do this for each viewController?
Q3) I'm using UIStoryboard and my first viewController is a UITabBarController. So do I register for the notification in the first tab's viewController?
I also have a singleton DataManager object that holds the data for the app if that helps anyone guide me in the right direction of where I should save my data. Thanks!
These methods are in the AppDelegate.m
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
You can perform your actions here. You can however register to "listen" to that event in another view controller (like your example) but that is just to make it easier to send that event notification into that viewcontroller.
1) no, only to ensure that whenver this VC is loaded it will be able to listen to this event.
2) no, only for the ones you want to pass the even easily like this. However using the appdelegate.m and each's vc view did appear is better.
3) depends on the kind of data you want to save, but typically you create your own file and just save it to disk like in any other OS. ios gives you access to the "documents" folder of your app and each folder is used for something specific, read the documentation.
Could anyone tell me when we use the AppDelegate.m and AppDelegate.h during iPhone programming? I have used only the ViewController.m and ViewController.h for basic learning. I just want to know when and why AppDelegate is used.
Both define classes, but the classes are used for different things. ViewController.h/m define a view controller class that manages a hierarchy of views -- basically, one screen of an application. You might have multiple screens that each have their own view controller.
AppDelegate.h/m define a class that manages the application overall. The app will create one instance of that class and send that object messages that let the delegate influence the app's behavior at well-defined times. For example, -application:didFinishLaunchingWithOptions: is sent when the app has finished launching and is ready to do something interesting. Take a look at the UIApplicationDelegate reference page for a list of messages that the app delegate can implement to modify the behavior of the application.
I would like to add the following to #Caleb's answer.
If care is not taken, the AppDelegate could easily become one of the most accessed objects in the application. I usually refrain from calling methods in the AppDelegate from any of my ViewControllers. Unless, something needs to be reported to the AppDelegate that would influence the behaviour of the whole application.
I keep my AppDelegate for the following:
initialization: whatever needs to be done on the very first launch (after an install or an update)
data migration from version to version (e.g. if you use CoreData and migrations)
configuration of objects linked via IBOutlets from MainWindow.xib
determining the initial orientation to launch in
saving uncommitted data / state prior to the application being terminated or entering background mode
registering for the Apple Push Notification Service and sending the device token to our server
opening one of the supported application URLs (e.g. maps://)
For other use case scenarios and a more thourough description of the AppDelegate, see the iOS Application Programming Guide.
The view-controller. h/m is responsible of controlling the connection between your model and your view (more on MVC here).
AppDelegate. h/m is responsible for the life-cycle of your application. What to do when the user press the home button and exit your app, what to do when the app enter background. Things like this.
I have two views in my app, one is a general view where CoreLocation works away calculating the users location while the user is doing other stuff in the view. The second view is accessed by the user when they touch a button allowing them to locate themselves more accurately using a mapview and MapKit, i would like the mapview in this view to show the location that CoreLocation has already identified in the first view AND to continue displaying this location based on updates from CoreLocation in the other view.
Is the best way here to create a singleton that encapsulates the CoreLocation stuff and have this referenced in the view with the map, or to use notifications ? or to use some other better practice for my scenario ?
Thanks
I have a couple of apps that use CoreLocation in multiple places. From what I've read, you definitely want there to be just one instance of CLLocationManager. It's worked great as a singleton for me.
Hope this helps!
If I were you, I would do it this way:
Decide which view is going to be always loaded.
I assume, you want CalculatingView is loaded all the time, and MapView will be loaded/unloaded based on the user action.
Allocate and initialize a pointer to CLLocationManager inside CalculatingView. This will provide location property and also call delegate messages. Since the CalculatingView is loaded and retained, this pointer is always working too.
Set CLLocationManager's delegate to be CalculatingView, which might also be called self, if this view has allocated and initialized CLLocationManager pointer.
Implement delegate methods of CLLocationManager, in CalculatingView
If you like to, you can have MapView to be allocated and initialized within CalculatingView. But it's ok to have it in other places, as long as you can send message to MapView. Make sure they are valid by checking if it's not nil or if it respondsToSelector.
When the CLLocationManager's delegate, which is CalculatingView receives messages, send a message to MapView.
It's like relaying messages, but the messages that MapView should respond to don't have to be the same messages sent to CalculatingView like delegate method calls from CLLocationManager
By checking if MapView is valid, meaning if it's loaded to be displayed, you can decide to send messages to MapView or not
The essence is to decide which view is loaded consitently, to use delegate methods for sending(or relaying) messages to other pointers(in this cases, MapView pointer).
The singleton is good, but unless you are going to use CLLocationManager from multiple places, like more than 3~4 places, it's not that necessary, I think
Hope I didn't confuse you. Based on what you posted, it seems like this way can be simple solution for your goal. If I didn't catch your true intention, please let me know.
I am not sure this is the best way, but I've been setting up my main controller (the one that is loaded first) as a location manager delegate. When the location updates it fires off a notification with the new location as the notification object. Any controllers listening can then use that data however they need it.
As an aside, Apple's LocateMe app instantiates the location manager three times. So, by their example, having multiple LocationManagers might not be a problem.
From what I've read, best practice for this is to add CLLocationManager to your App Delegate as you can access it from any view.
Short sample code to put in your view where you need the CLLocationManager
....imports....
#implementation YourViewController
- (void)viewDidLoad {
self.myLocationManager = [[UIApplication sharedApplication] delegate].yourLocationManagerVarName;
}
#end
Hop that helps.
Maybe you should consider a MVC oriented approach. From your description your are missing a model layer representation of your user. Defining a simple User class with a basic CLLocation property would be a first step.
#interface User {}
#property (nonatomic, retain) CLLocation *location;
#end
#implementation User
#synthesize location;
- (void)dealloc {
self.location = nil;
[super dealloc];
}
#end
The same instance of the User will be passed to your view controller. It may be created in the app delegate.
Next create location services object for your app. It will start the CLLocationManager, and give the location to your user. You may have to set the GPS accuracy, ignore frames you don't want, and implement basic LBS logic here.
At this point, you have a feature full app, without any UI. This is a good design in the way it can be reused and tested.
Now stack your UI on top of that. Give your root controller a pointer to the User instance in your app delegate. Your view controller pass this pointer to modals / navigations view controllers it creates.
This controller start observing User's location changes in their viewDidLoad and react accordingly.
- (void)viewDidLoad {
[self observeValueForKeyPath:#"location" ofObject:self.user change:0 context:NULL];
}
Your view controller would also register for notification raised by your location services objects to display an alert to the user.
Based on other answers:
there is no real penalty to create multiple CLLocationManager instances in your code. The only side effect is that the api is asynchronous, thus you have to wait to get a valid location in your view controller. You can try to get the current location from the location manager on your viewDidLoad using locationManager.location API.
don't share stuff from your app delegate. This prevent code reuse. What if you reuse your views and you app delegate don't have a location manager ?
if you need more code, please ask.
Im just wondering if there is any method of catching any user interaction with the application.
The reason i ask is that when a user interacts with the app i update a date in the db. if they date is older than 10 minutes they are seen as offline by other users until they comeback and interact with the program.
Does anybody have any ideas on how i could catch any user interaction to update this field?
Thanks
p.s. it is a navigation app. so even if i can add a handler to the navigation controller to say when a page is changed that might do???
The most convenient way would probably be to subclass UIApplication and override the sendAction:to:from:forEvent: method. You will also need to add a key to your Info.plist file called “NSPrincipalClass” with a string value containing the name of your subclass, which tells UIKit to your subclass in place of UIApplication.
MyApplication.m:
- (BOOL)sendAction:(SEL)action to:(id)target
from:(id)sender forEvent:(UIEvent *)event
{
ResetInterationTimeout();
return [super sendAction:action to:target from:sender forEvent:event];
}
Info.plist:
<key>NSPrincipalClass</key>
<string>MyApplication</string>
If by interaction you mean 'touches' then you can easily do that by putting a UIView (if do not have a global one on top of the others) on each UIViewController in your NavigationController that has the duty of registering a touch, saving the current date to an higher level controller (even the AppDelegate might work). Then this controller can compare the date to the previous one ( you have to store it) and if the time difference overcomes your threshold you can fire your action by messaging the proper object.
Here is a guide from Apple on how to catch the touches (you will need to overrid the touchesBegan:WithEvent: method to get the first touch)
I am developing an iPhone application with multiviews (Nav controller), but i like to receive an event if user touches in any view of the view. I understand it can be done by subclassing application delegate? If that's true how can i do it? My requirement is, i like to receive an event as soon as user touches any where in any view within my application.
Thanks for your help and time.
Your reference to subclassing UIApplication will work. Read down through the comments and it covers a somewhat quirky IMO way to implement it (by having the AppDelegate be a subclass of UIApplication). Myself, I would create a separate class to be the UIApplication subclass, rather than having the app delegate do both jobs, but I see the merit of either way.
That said, this is a very large and unusual stick and may suggest a design failure. What problem are you solving with this?
A way to do it is to use a Singleton class (which acts as an observer/mediator), which the application is an example of, in which you have viewControllers subscribe to when they are intersted in the touch events of a certain view. When the touch occurs the Singleton class is informed of the event as a result it informs all subscribers to the event of the event.
Here is an example
#interface MyEventClass
{
-(void)TouchEventDidOccur;
-(void)subscribeToTouchEvent:(id)delegate selector(selector):sel
}
Above is the singleton class
now this is an example of what the view touchesBegan method might look like
-(void)touchesBegan...
{
[[MyEventClass sharedInstance] TouchEventDidOccur];
}
and how one would subscribe to the event
[[MyEventClass sharedInstance] subscribeToTouchEvent:self selector:#selector(receiveTouchEvent:)]
hope this helps
What's wrong with using notifications? If you have disconnected classes across your application, it's trivial to have them listen for a particular notification, then have your views or view controllers post that notification when a touch event happens. All of the observers will take action on the notification.