Enable a GIT Repository for an Existing Project
I’ve only recently started using GIT to handle version management in my X-Code projects (I’ve just been using snap shots up until now), so have a number of projects that I needed to enable GIT version management for. Here’s how to do it:
- Close any open projects and close X-Code.
- Open up the terminal in OS X.
- Navigate to the project directory (say \Users\Craig\X-Code Projects\My Project).
- Enter the following commands:
- git init
- git add .
- git commit – m “initial commit (or what-ever comment you want to use)”
- Start X-Code and load your project, X-Code should pick up your GIT repository automatically.
To check for a GIT repository in a particular project, open the project and then switch to the Organizer either by clicking the right toolbar button in the project window or selecting Organizer from the Window menu. In the Organizer, click the Repositories icon and make sure your project is listed down the left hand side. If it’s not, use the steps above to enable GIT for the project.
Once GIT is enabled, you should start to see the “A”, “M” etc icons along side the files in the Project Navigator and be able to commit changes from Source Control on the File menu (or by right / ctrl-clicking).
Core Data – Part 1: Introduction
So, I’ve been working on using Core Data to save route information in FootPath rather than NSKeyedArchiver which is what the app is currently using. This is all down to performance reasons, since the more I use the app on my own iPhone 4 and the more routes I store, the longer it’s taking NSKeyedArchiver to save the data, and it’s now taking several seconds to store a new route or re-save the data after deleting one from the home screen. This is quite obviously, pants, so I figure Core Data is the way to go and hopefully it’ll give me the performance improvements I need, plus it seems like a good opportunity to learn about it. First, let me give you a high level overview of how FootPath works to give you an idea of the data I’m saving and how I’m using it.
The Problem
- When the app starts, all the saved data is un-archived into a master NSMutableArray.
- That array is scanned through and separate arrays for each week are generated, which are then used to build the table view.
- The user taps the New button, the map screen is loaded which initialises a CLLocationManager object and starts getting location updates.
- Once the horizontal accuracy for the generated location data has become a positive value, the app plots the users position on the map and displays the start button.
- When the user taps the start button, a new route object is initialised and passed the current location object and date. The route object stores these in it’s own NSMutableArrays.
- Further location objects are passed every time location services updates it’s location, once a KM or mile has been reached, these locations are stored in additional arrays.
- When the user exits the map screen and chooses to save, the route object is passed to the home screen’s view controller, which adds it to the master array and archives that array.
- When the user taps on an entry in the table from the home page, the appropriate route object is loaded from the master array and passed to the detail screen’s view controller.
- The detail screen view controller uses the location objects stored in the internal arrays of the route object to display the route on it’s map view. The mile / KM arrays are used to position the split pins.
The underlying problem is that I’m storing a bunch of route objects (that in turn store a bunch of location objects) in an array and then need to archive the whole array of objects to the application’s Documents folder each time I save. The more objects in the array, the longer it takes to save, so I need to look at alternatives.
Objectives
Well, the first thing I learned about Core Data is that it’s not the easiest of subjects to pick up for a relative iOS new-be like me, especially since I wanted to understand how to store several arrays of data rather than a simple object. There seem to be endless examples on line, but pretty much all of them fell into one of two camps as far as I could tell: They were either well documented but quite simple and only covered storing simple data structures or they covered more complex data structures but were pure code examples that lacked any decent (or any at all) documentation. So I figure it’s worth while documenting my progress here in a series of posts as these may help others who are starting to look into using Core Data in an existing app, or at the least it’ll help me to better understand and remember what I’ve learned.
The first resource I really found useful was the Core Data Tutorial for iOS from Apple. This falls into my well documented but simple example category, but at least it got me started and I recommend you work through it. I don’t plan to just effectively repeat it’s content here since it already does a perfectly good job of describing what core data is, how to create the object model, entities, attributes and NSManagedObjects you need, along with how to load, delete and save data. What I plan to do in this post is talk about how I decided on the design of my object model, and how I mapped my data to the entities and attributes available in core data. In later posts I’ll expand on the example given in the apple document (another reason to work through it) to show how I determined how to store the information from my various arrays by creating additional entities and one to many relationships in core data.
Mapping My Data to Core Data
Once I’d worked through the apple document, I could setup and use core data in a simple example, but I still had a number of questions I needed to work out answers to, namely:
- Thinking of core data in terms of a database. Each entity is a database table (and therefore record), each attribute is a field used to store specific data for that record. I needed to decide how my data maps to this model, what database tables did I need to create and what fields did I need in each table.
- Each entity maps to an NSManagedObject (along with corresponding header and interface files), whilst each attribute maps to a property within the NSManagedObject. I needed to understand how these NSManagedObjects would fit into my existing classes. Does my route class need to be a subclass of NSManagedObject for example.
- Each item I want to save has additional arrays of data. How do I save a single object in core data that has additional arrays of data?
To help answer the first question, I needed to consider the data that the app generates. As already mentioned I’m currently storing arrays of objects (principally route, location and date) as can be seen by the init method for the route object:
- (id)initWithStartLocation:(CLLocation *)startLocation andStartTime:(NSDate *)startDate
{
if (self = [super init]) {
self.routeCoordinates = [NSMutableArray arrayWithCapacity:1];
self.mileCoordinates = [NSMutableArray arrayWithCapacity:1];
self.mileTimes = [NSMutableArray arrayWithCapacity:1];
self.kmCoordinates = [NSMutableArray arrayWithCapacity:1];
self.kmTimes = [NSMutableArray arrayWithCapacity:1];
self.totalDistance = [NSNumber numberWithDouble:0.0];
[self.routeCoordinates addObject:startLocation];
[self.mileTimes addObject:startDate];
[self.kmTimes addObject:startDate];
}
return self;
}
As you can see, I’m setting up a number of time and coordinate arrays for each route object I initialise and then use them to store CLLocation and NSDate objects. However, if we look at the data types available in core data, it soon becomes apparent that short of encoding each array to and from NSData objects, I can’t just simply store these objects in core data:
I needed to think about what I wanted to save, why I wanted to save it and what format I needed to save it in. Lets take a look at the home screen for FootPath and consider what data is being displayed here:
- The title bar displays the total distance travelled across all routes. This needs to be calculated each time the home screen is displayed as it’s obviously dependant on the routes displayed in the table. Total distance is simply the sum of all route distances, so we need to make sure the route distance is stored as a numeric value and, since the distance is displayed in either miles or kilometers depending on the user settings, we’ll store the value for distance in meters so that we can convert it as needed.
- The table section headers display the date for the week (I use Monday as the first day of the week). This is generated when we first load the home screen and uses the date of each route, so we need to ensure we’re saving that but don’t need to save the generated week data itself as this will change as we add more routes and delete others.
- The table cell displays the date and time of the route, along with the distance and time taken for the route. We already have the date and distance covered so just need to consider time taken. I’m not really doing anything with the time taken data either here or on the details screen, other than displaying it.
- The table section footers display the total distance and calories used for all the routes in each week. Along with distance, we therefore also need to be storing calorie usage for each route as a numerical value so that we can calculate this.
What can we determine from this? Well, since we need to save, display and delete each route separately we need to define a route as an entity in our core data object model. Also we know that each route entity will need the following attributes:
- Distance (in meters) stored as a numeric value. This is a double value within the app, so that’s what we’ll use in the object model.
- Date and time for the route (core data allows us to store an NSDate object directly using the Date type).
- Time taken for the route. This could be stored as a numerical value if we needed to do something with it later but I’m using a string since I simply need to display it.
- Calorie usage for each route stored as a numerical value. This is a float value in the app, so we’ll use that data type in core data.
We need to also consider the requirements of the detail screen since this also displays route data:
- Route distance and time, which we already have from the home screen.
- Start location. Currently, I’m storing the full CLLocation object as generated by core location in my routeCoordinates array, but I can’t do that in core data. The Core Data Tutorial for iOS example shows how to store location data, get the longitude and latitude values and store each one as a separate double value in core data, so that’s what we’ll do.
- Finish location. See start location.
- Split locations. These are the coordinates for each mile or kilometer of the route, I’ll store them the same way I’m storing the start & finish coordinates, but I need to store several of them for each route.
- The route. This is the routeCoordinates array, with the first location object stored defining the start location and the last defining the finish. Obviously there’s a ton of location data to save for each route so again it comes back to how I store an array of objects in core data.
- Time for each split. This is the time taken to travel a mile / kilometer or the final split to the finish. Again it’s only being displayed, so it can be stored as a string, but there are potentially going to be several of them, one for each split location.
- Calories used. We have this in our list of attributes already.
- Average speed. Even though we only display this, we need to display it in either mph or km/h depending on settings, so we’ll store it as a numeric value to make conversion easier.
And there we have it, a pretty good map of the data we need to store and what attributes we need to create in our core data object model. In reality, there’s a couple of additional strings I’m storing that are used to setup the weeks used by the table view and to ease displaying some other info, so the full object model for a route looks like the screen grab below:
That’s it for part one. In the next part I’ll expand on the Apple tutorial to show how to add additional entities and relationships into your object model and how to save data to them. Finally I’ll show how I’m storing my coordinate arrays in core data and how I go about migrating existing NSKeyedArchive data in the app across to core data at first launch.
Customising Action Sheets
I wanted to customise the button order in an action view that I was creating for one of my apps, so I thought I’d document the process. First lets look at the normal way of initializing a new UIActionSheet:
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@”Action Sheet” delegate:self cancelButtonTitle:@”Cancel” destructiveButtonTitle:@”Destructive” otherButtonTitles:@”Button 1″, @”Button 2″, nil];
[actionSheet showInView:self.view];
[actionSheet release]
Which produces the following action sheet:
The destructive button is at index 0 (top), cancel is at the bottom (index 3 in this case) and any other buttons are in between. Which is fine if I wanted the standard layout, but I wanted the buttons to be in a different order, so I took a look at the UIActionSheet class reference document and noticed two properties that looked like they would do the trick, namely cancelButtonIndex and destructiveButtonIndex. The properties are not read only, which means we can set them, so let’s give them a whirl by adding the following two lines to the above code before we call showInView:
actionSheet.cancelButtonIndex = 1;
actionSheet.destructiveButtonIndex = 2;
This makes the action sheet look like:
Now, I should point out that if you look at the discussion section for the relevant property reference, you’ll come across a statement like the one below which is from the cancelButtonAtIndex reference:
“Button indices start at 0. The default value of this property is normally -1, which indicates that no cancel button has been set. However, a cancel button may be created and set automatically by the initWithTitle:delegate:cancelButtonTitle:destructiveButtonTitle:otherButtonTitles: method. If you use that method to create a cancel button, you should not change the value of this property.”
I think we can see from the above example why the button index properties shouldn’t be set when usinginitWithTitle:delegate:... Although it will technically work – all we are really doing by setting a button to either cancel or destructive using the properties is changing it’s colour to black or red respectively. There’s nothing else that distinguishes those buttons from the other two we’ve defined, and in the action view’s delegate method we use the passed buttonIndex value to determine which action to take. What it does do is make out code confusing and difficult to follow – the destructive and cancel buttons defines in the init method are not necessarily the destructive and cancel buttons the user will see. So, what’s the correct way of changing the button order in an action sheet?
Well, it’s to initialise simply with init and then to use the addButtonWithTitle: method to add each individual button in the order you want them listed like so:
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
actionSheet.delegate = self;
actionSheet.title = @”Action Sheet”;
[actionSheet addButtonWithTitle:@"Button 1"];
[actionSheet addButtonWithTitle:@"Button 2"];
[actionSheet addButtonWithTitle:@"Destructive"];
[actionSheet addButtonWithTitle:@"Cancel"];
[actionSheet showInView:self.view];
[actionSheet release];
The order we add the buttons in the method above is the order that they will be displayed in the action view, with the first button at index 0 and so on:
Hmm, that’s better – the buttons are in the order we want, but what happened to displaying the destructive button in red and the cancel button in black? Well, we haven’t specified which of our buttons are the destructive or cancel ones, that’s what the two properties we tried earlier are for. So let’s add the appropriate lines to our code, bearing in mind that our destructive button is at index 2 and our cancel button is index 3:
actionSheet.destructiveButtonIndex = 2;
actionSheet.cancelButtonIndex = 3;
Which gives us exactly the result we want, but we’re not quite done yet. Take a look at the addButtonWithTitle: reference and you’ll see that it returns an NSInteger which just happens to be the button index, so we can combine our property and add button calls into a single line, like so:
actionSheet.destructiveButtonIndex = [actionSheet addButtonWithTitle:@"Destructive"];
actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:@"Cancel"];
So that’s it, you can now create action sheets with custom button ordering. There’s one more property that’s worth having a play with, and that’s actionSheetStyle. this lets us define the look of the action sheet using one of the defined constants:
-
UIActionSheetStyleAutomatic -
UIActionSheetStyleDefault -
UIActionSheetStyleBlackTranslucent -
UIActionSheetStyleBlackOpaque
Automatic will take on the style of the bottom bar, otherwise it will look the same as default (shown in the examples above). Translucent will show whatever is behind the action sheet whilst opaque is solid black as below.
Hope you find this useful!
Add a viewController to the Empty Application Template in X-Code 4.2.1
Following on from me wanting to recreate the window based application template in X-Code 4.2.1, I decided to reverse engineer adding a view controller to the blank application template. Might be useful for some (and me when I loose my notes!)
- From your empty application, create a new UIViewController and XIB file. From now on, I’ll refer to this view controller simply as ViewController, and you should substitute your view controller’s name instead of this. For example, if you called your view controller “MyViewController”, on the next line you should use the command: #import “MyViewController.h”.
- Open the application delegate header file and add the #import “ViewController.h”; line.
- Open the application delegate implementation file and add the line ViewContoller *viewController;
- in the -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method, directly above the line [self.window makeKeyAndVisible]; add the following to additional lines:
- viewController = [[[ViewController alloc] initWithNibName:@”<xibname>” bundle:nil] autorelease];
- self.window.rootViewController = viewController;
- Finally add [viewController release]; to the dealloc method (creating the method if it doesn’t exist).
My First App Store Submission
I’ve been working on a personal app project for the last month or so, and today I decided that I’ve really done enough code tweeking and really should get on with submitting it the app store. So that’s what I’ve done this morning, it’s my first app submission (but hopefully not my last), and I’ve got to say, it’s not the most obvious process in the world, so I’ll probably create a blog post detailing the steps so I can remember for next time!
For details of my app, look here.
Creating an iPhone Window-based Application in X-Code 4.2.1
About three weeks into learning Objective-C, I installed X-Code 4, and this is where I hit one of my first hurdles. A lot of the books and Internet resources I was using at the time based their exercises on the Window-based application template available in X-Code 3, and missing from version 4. Looking at the available templates in X-Code 4, it looked like both the blank application and single view templates where close to what I needed, but neither exactly matched the window based template that the samples used. Time to reverse engineer my own window based app in X-Code 4.
- Create a new project using the empty application template. I didn’t want to use storyboards or automatic reference counting, so I left those options unchecked.
- Once you have your blank application, on the File menu, select New > New File.
- On the template selection screen, highlight User Interface under iOS, select the Window icon and click Next.

- Select the platform (iPhone for me) and name the file MainWindow.
- Move your new MainWindow.xib file to the appropriate group in the project navigator window, and with the file selected, click on File’s Owner in the Placeholders section of the dock to the right.

- Use the Identity Inspector to change the class to UIApplication.

- Now, look in the library and drag an Object into the Objects section of the dock above Window.

- Using the Identity Inspector, change the class of the Object to the Application Delegate class for your project (take a look at the name in the project navigator pane). This will also rename it in the dock to match.

- Open your application delegate header file
- Locate the @property line for the UIWindow property and modify it to read @property (strong, nonatomic) IBOutlet UIWindow *window;
- Now open MainWindow.xib again.
- Right click on File’s Owner and drag from delegate under Outlets to the application delegate object in the dock you added earlier.

- Now right click the application delegate object and drag from window under Outlets to the Window object in the dock.

- Click your project name at the top of the project navigator to display the project summary page.
- In the Main Interface drop down, select MainWindow.

- Finally open your application delegate implementation file and in the didFinishLoadingWithOptions method, remove all lines except [self.window makeKeyAndVisible]; and return YES;.
You’re done, you should now have a useable copy of a window based application template in X-Code 4.























