There are a couple of ways to accomplish real time tracking via an iPhone or iPad including dedicated OS apps like Find My iPhone, but what if we need that information integrated into our own systems? One method of accomplishing this is to have the device loaded with an internal “Enterprise” application. They way you implement this application is dependent upon the specific needs of the user. You can restrict the device to single app mode where the Enterprise application is always open and on screen. This would allow the app to consistently update on the current GPS location. Or, if the user needs to be able to multitask and use multiple applications, you will need to include some additional code to allow the GPS monitoring process to continue in the background when the application is not on screen. For the purposes of this blog, we will focus on simply accomplishing the task of GPS monitoring and assume that the application is in the forefront or locked to single app mode.
After creating a new project in XCode, select a Single View Application under iOS.
Name the project, for the purpose of this example we named the project gpsSingletonExample.
Once the project is loaded, we need to include the CoreLocation framework to have access to the user’s location data. Under Linked Frameworks and Libraries click the + symbol and select the CoreLocation.framework to add.
Now that we have the necessary framework, right click on the gpsSingletonExample folder in the File Explorer and select New File
Choose Cocoa Touch Class, change the Subclass to that of NSObject, and name the class GPSObject
We have added the CoreLocation framework to the project, but we also need to import it into the GPSObject. In GPSObject.h below the Foundation Import, add @import CoreLocation; and add CLLocationManagerDelegate to the @interface declaration.
Now we need to declare a few properties. We will need a CLLocationManager to handle the gathering of the GPS data, we will need a CLLocation object to store the data, and we will also declare an NSTimer to allow us to control how often we send updated data.
Now that we have our properties, we also need to declare a few methods. We need 2 public methods, and a private method to initialize the properties. Declare the getInstance method to return the GPSObject for use, the destroy method to get rid of the resources when we are done, and the initializeManager method to get everything ready for us.
Now that all that is taken care of, let’s move on to the GPSObject.m file. This is where we put the code to handle our Singleton Creation, Logging the GPS Coordinates for the Device, and also where you can put your customized code to do what you will with the coordinates once they have been gathered.
We start by synthesizing our variables below the @implementation declaration. Do this for the locationManager, assetLocation, and gpsUpdater.
Below that, we need to declare our instance variable. We will set it to nil for now, that way when we call our object for creation, it will recognize that it has not yet been set up and perform the setup process.
After setting everything up, let’s handle the creation of the instance of our object. The following public method will synchronize our singleton, check to see if the instance has yet been created, create it if it hasn’t, and then return the instance. Ignore the errors you will see on the [instance initializeManager] line, that will correct itself once we write that method.
Now that we have our creation method, let’s write our destroy method. We will use this once we are finished with our singleton. This can be used when a user logs out, when the app is closed, or any other circumstance where you want to stop monitoring the device.
In this method, we will invalidate the Timer (We will create it in another method), destroy our instance by setting it to nil, and then returning nothing.
Now that we can create and destroy our instance, let’s work on setting it up. In the initializeManager we will invalidate any previously created gpsUpdater timers, allocate memory for our locationManager and set it’s delegate to the object, make sure the application has permission to access the user’s location (We will finish this process later), set the desired accuracy for the GPS monitor (Here we have simply set it to the best possible accuracy, this is battery intensive), and start updating the location. Once we have that taken care of, we also need to set our update timer.
Our locationManager is now set up, we need to handle what happens when the device location updates. We do this with the didUpdateLocations method. In the method, we will record the last updated location to our assetLocation variable.
Now we need to tell the application what to do when our timer goes off. In the previous method, we set the timer to go off every 60 seconds. The reason for this is that if we simply sent out updates every single time the GPS location updated, we would be firing off updates multiple times a second. This can get processor intensive, battery intensive, and possibly clog up our server. Now, for the purpose of this sample, I am only showing you how to set the timer and simply printing out the coordinates to the log. What you do with the coordinates is dependent on your application. You can include code here to send to coordinates back to your server, save them to a log, or whatever else your particular needs require.
We are now finished with our GPS Singleton. Below is the finished implementation file (GPSObject.m).
Now, in order for our application to work it has to have permission to access the user’s location. We started that process in the initializeManager method. In order for that requestAlwaysAuthorization command to work, we have to have a key in our project that describes our need for the data to the user. In order to do that, click on the Project at the top of the File Manager, go to the Info Tab, beside one of the existing entries click the + symbol, and add the following for the key:
And for the value include a meaningful message about why you need the data. For this example we simply put “Message about using the location.”
We have finished out Singleton and told our application how to handle requesting Location Permissions. Now, all that is left is to create our singleton. Go to the ViewController.m file and add in an import for GPSObject.h (#import “GPSObject.h)
Under the @implementation declaration, declare a global GPSObject variable named _gpsObject.
And finally in the viewDidLoad method, set that _gpsObject equal to the creation of a new GPSObject instance using:
_gpsObject = [GPSObject getInstance];
And we are done! Run the application and after being prompted to allow Location Services you will see the GPS coordinates pop up in the Log Viewer ever 60 seconds. In order to implement the destroy method simply put in the code :
_gpsObject = [GPSObject destroy];
Now that you know how to create and use the singleton, customize the timer method to handle the coordinate data in a way that suits your needs. You can include the ViewController code in any controller that is appropriate and since this is a singleton it will continuously update no matter where you are in the application after it’s creation.
The source code for the example can be found here!