Categories
Swift Kick

How to work with dates and times in Swift, part one [Updated for Swift 2]

i just want to use dates

Update, August 26, 2015: I’ve updated this article so that its code works with Swift 2. It compiles under the latest version of Xcode 7, beta 6.

swift kickIf you’re just getting started with date and time programming in Swift, chances are that you probably did some Googling, found NSDate and its companion classes in Apple’s documentation and promptly got confused. Let me reassure you that it isn’t your fault. Apple’s Date and Time Programming Guide isn’t set up in the most helpful way, and its examples are in Objective-C, which can throw you off if you’re not familiar with its [instance method] calling syntax.

If you’re coming to Swift from JavaScript, which makes do with a single object type called Date, the idea of having this set of classes just to handle dates and times looks like overkill:

cocoa date time class chart

Click the chart to see it at full size.

This is the first article in a short series on programming dates and times in Swift. It’ll help you make sense of working with NSDate and its companion classes.

What is UTC? (or: “It’s 5 o’clock somewhere!”)

what time is it right now

People who like to drink are fond of saying “Well, it’s five o’clock somewhere!“, and it’s my favorite way of illustrating that what time it is depends on where you are. It’s why we have UTC — Coordinated Universal Time — the “One True Time” on which every other time zone is based. UTC replaced GMT (Greenwich Meridian Time, the time as observed at the Royal Observatory in Greenwich, London), and it doesn’t change for daylight savings. By having this standard, we eliminate the confusion that comes up when discussing times.

While most places have some names to refer to time zones in everyday conversation — such as Pacific, Mountain, Central, and Eastern in North America — the clearest way to indicate time zones is to express them as negative or positive offsets from UTC. For example, the North American time zone known as “Eastern” is 5 hours behind UTC, so it’s expressed as UTC-05:00. There are certain time zones where the offset isn’t whole hours, such as Newfoundland’s, which is UTC-03:30, and Nepal’s, which for some reason is UTC+05:45.

NSDate: Cocoa standard time

When you want to represent a date or time in Cocoa, you do so with an instance of the NSDate class. Here’s a nice, simple description of what NSDate is:

nsdate

When you’re measuring time, you need a reference point. The Gregorian calendar — the one that I’m 99.999999% sure that you’re using right now — uses what is said to be the year of the birth of Christ as its reference point. Your age uses the date of your birth as a reference point. A time trial race uses the time at the start of the race as its reference point.

NSDate‘s reference point is the start of the third millennium: January 1, 2001 at midnight UTC. It stores time as an NSTimeInterval, a 64-bit floating point value representing a number of seconds. Negative values represent a number seconds before January 1, 2001, 00:00 UTC, and positive values represent a number seconds after that time. According to Apple’s documentation, this representation of time “yields sub-millisecond precision over a range of 10,000 years”, which means that an NSDate instance can represent any point in time from about 3000 BC/BCE to 7000 AD/CE.

Here are 4 historical dates, as seen from NSDate‘s perspective:

historical dates nsdate style

There are some consequences to the fact that NSDate treats time as an offset of seconds:

  • All NSDate values refer to both a date and a time. If you want to use an NSDate to store a date only, you ignore the time portion, and vice versa.
  • NSDate has no concept of time zones or any time unit other than seconds. That means you can’t ask it what year, month, day, hour, or minute correspond to the time it’s storing. As far as it’s concerned, there are no calendars; you work with NSDate‘s representation of time, when it’s time to display a date, time, or both, you format it to use the calendar and time zone that’s appropriate for the user.

There’s a method to this madness: it allows us to use and store dates and times in a way that’s independent of calendar systems, time zones, languages, and date formats. As I write this, it’s the year 2015 in the Gregorian calendar, but the Buddhist calendar says it’s 2558, and if you go by the Hebrew Calendar, it’s 5775. I may say it’s 9:45 a.m. as I write this in Tampa, but if you’re in California, it’s 6:45, and if you’re a soldier, you might call it 14:45 Zulu Time. I call the current month January, but you might call it Enero or Janvier. It’s all the same as far as NSDate is concerned, which makes it incredibly flexible.

Creating NSDates without any helper classes: now is easy, other dates ain’t so pretty

Let’s create some NSDates right now. Fire up Xcode, open a new playground, and enter the following code so that it looks like this:

// Playground - noun: a place where people can play

import UIKit

let now = NSDate()
print(now)
now.timeIntervalSinceReferenceDate

You should see results in the sidebar that look similar to this:

playground 01

If you create an NSDate without any parameters, you get an instance representing the date and time at the moment it was created. That’s what we’ve done by creating the instance named now.

Note that in the sidebar beside line 5, where we created now, the result displayed in the sidebar is Jan 19, 2015, 8:52 AM. While the internal representation of the current time is a 64-bit floating point value, Xcode’s doing us a favor by representing it in a more readable format and using the local time zone. It’s doing this by making use of a date formatter, which we’ll cover later.

In line 6, we’re using the println function to display the default string representation of an NSDate, which is a completely numeric one. It’s more readable than a 64-bit floating point value, but it might not be in the format or time zone (or even the calendar system) that you want. Once again, this output comes courtesy of a date formatter.

Finally, in line 7, we use the timeIntervalSinceReferenceDate property to display now‘s internal representation of the date and time it’s storing: about 443 million seconds after January 1, 2001 at midnight UTC.

Let’s create the dates from the Historical dates, NSDate style picture above. Enter or paste the highlighted code below so that your playground looks like this:

// Playground - noun: a place where people can play

import UIKit

let now = NSDate()
println(now)
now.timeIntervalSinceReferenceDate

// March 10, 1876 was 3,938,698,800 seconds before the third millennium (January 1, 2001 midnight UTC)
let firstLandPhoneCallDate = NSDate(timeIntervalSinceReferenceDate: -3_938_698_800.0)

// April 3, 1973 was 875,646,000 seconds before the third millennium
let firstCellPhoneCallDate = NSDate(timeIntervalSinceReferenceDate: -875_646_000.0)

// January 9, 2007, 18:00 UTC was 190,058,400 seconds after the third millennium
let iPhoneAnnouncementDate = NSDate(timeIntervalSinceReferenceDate: 190_058_400.0)

// January 27, 2010, 18:00 UTC was 286,308,000 seconds after the third millennium
let iPadAnnouncementDate = NSDate(timeIntervalSinceReferenceDate: 286_308_000.0)

Note my use of the underscore character, _, to act as a “thousands” separator. It’s not required; it just makes large numbers easier to read.

In the sidebar, you should see nicely-formatted dates beside the NSDates you created:

playground 02

Click the screenshot to see it at full size.

NSDate has four initializers for creating specified dates and times:

Initializer Description
init(timeIntervalSinceReferenceDate:) Create an NSDate instance representing a time specified by a number of seconds before or after January 1, 2001 00:00 UTC.
init(timeIntervalSinceNow:) Create an NSDate instance representing a time specified by a number of seconds before or after the current date and time.
init(timeIntervalSince1970:) Create an NSDate instance representing a time specified by a number of seconds before or after January 1, 1970 00:00 UTC. This method exists not because Apple’s founders were California hippies nostalgic for the era of their youth, but for compatibility with Unix time.
init(timeInterval:sinceDate:) Create an NSDate instance representing a time specified by a number of seconds before or after a given NSDate.

You’ve probably noticed that none of these initializers lets you create an NSDate by giving it something convenient like a year, month, day, time zone and so on. Luckily, there are classes that will help us do this.

Creating NSDates with the help of NSCalendar and NSDateComponents

If you’re like most people, you’d probably much rather initialize a date object using a day, month, year, and time instead of some number of seconds before and after midnight on January 1, 1970, January 1, 2001, or any other arbitrary date. For this, we’ll need a couple of additional classes:

nscalendar and nsdatecomponents

First, there’s the NSCalendar class, which among other things, gives us a context for converting NSDate‘s “seconds before or after the third millennium” measurements into a familiar time system with years, months, days, hours, and minutes, and it accounts for time zones as well. Most of the time, the date and time system will be the Gregorian calendar, but iOS also lets you choose from 15 other calendar systems, including Hebrew and Buddhist.

Next, there’s the NSDateComponents class, which is an assembly of properties that make up a date, such as year, month, date, hour, minute, second, and so on. An NSDateComponents instance can be used to represent either:

  • A specific point in time, or
  • a duration of time.

To create an NSDate by specifying things like a year, month, day, and time, we’ll do the following:

  • Create an NSCalendar instance pointing to the user’s calendar
  • Specify a date using an NSDateComponents instance
  • Create the NSDate by passing the NSDateComponents instance to NSCalendar‘s dateFromComponents instance method

nsdatecomponents to nsdate

Let’s go back to our playground and create our first historical date: that of Alexander Graham Bell’s first phone call. We know it took place on March 10, 1876. While we don’t know the exact time it happened, we do know that it happened in North America’s Eastern time zone, as opposed to something like Kiritimati, a.k.a. Christmas Island. That place is 19 hours ahead and would’ve resulted in historians recording that day as March 11th rather than the 10th.

Enter or paste the highlighted code below so that your playground looks like this:

// Playground - noun: a place where people can play

import UIKit

// The user's calendar incorporates the user's locale and
// time zones settings, so we'll often use it.
let userCalendar = NSCalendar.currentCalendar()


// March 10, 1876
// In this case, we're using an NSDatesComponents instance
// to represent a date rather than a duration of time.
let firstLandPhoneCallDateComponents = NSDateComponents()

// We don't know the time when Alexander Graham Bell made
// his historic phone call, so we'll simply provide the
// year, month and day. 
// We *do* know that he made that call in North America's
// eastern time zone, so we'll specify that.
firstLandPhoneCallDateComponents.year = 1876
firstLandPhoneCallDateComponents.month = 3
firstLandPhoneCallDateComponents.day = 10
firstLandPhoneCallDateComponents.timeZone = NSTimeZone(name: "US/Eastern")

Any calendar, regardless of its time zone, to turn date components into dates using its calendar system. If you specify a time zone in the date components, it will take that time zone into account; if you don’t specify one, the date will be created using the calendar’s time zone. We created an instance of the user’s calendar, which incorporates the user’s local and time zone settings, because it’ll be useful later when we want to go in the opposite direction and convert dates into date components.

Note that after setting the year, month, and day properties of firstLandPhoneCallComponents, we set the timeZone component using the preferred initializer, init(name:), which lets you specify a time zone by any of the standard string identifiers listed in the tz database of time zones. I could’ve used one of the city names such as America/New_York (or for those of you familiar with Canada, America/Toronto, America/MontrealAmerica/Atikokan, or America/Pangnirtung) to specify the Eastern time zone. It’s far clearer — especially to people not from the U.S. — to use the time zone names that begin with US or Canada, such as US/Eastern, US/Central, US/Mountain, and US/Pacific rather than city names.

Once we’ve set up the date components, we use the calendar’s dateFromComponents instance method to convert them into a date. I’m in the US/Eastern time zone, the same one as the one specified in the date components, so the result in the sidebar beside this line of code shows as “Mar 10, 1876, 12:00 AM” (we didn’t specify a time in the date components, so the resulting date has the default time of 00:00). The date displayed in the sidebar uses your system settings, which may be different from mine.

Let’s enter the other three historic dates. Enter or paste the highlighted code below so that your playground looks like this:

// Playground - noun: a place where people can play

import UIKit

// The user's calendar incorporates the user's locale and
// time zones settings, so we'll often use it.
let userCalendar = NSCalendar.currentCalendar()


// March 10, 1876
// In this case, we're using an NSDatesComponents instance
// to represent a date rather than a duration of time.
let firstLandPhoneCallDateComponents = NSDateComponents()

// We don't know the time when Alexander Graham Bell made
// his historic phone call, so we'll simply provide the
// year, month and day. 
// We *do* know that he made that call in North America's
// eastern time zone, so we'll specify that.
firstLandPhoneCallDateComponents.year = 1876
firstLandPhoneCallDateComponents.month = 3
firstLandPhoneCallDateComponents.day = 10
firstLandPhoneCallDateComponents.timeZone = NSTimeZone(name: "US/Eastern")

// We have a calendar and date components. We can now make a date!
// On my system (US/Eastern time zone), the result for the line below is
// "Mar 10, 1876, 12:00 AM"
let firstLandPhoneCallDate = userCalendar.dateFromComponents(firstLandPhoneCallDateComponents)!


// April 3, 1973
let firstCellularPhoneCallDateComponents = NSDateComponents()
firstCellularPhoneCallDateComponents.year = 1973
firstCellularPhoneCallDateComponents.month = 4
firstCellularPhoneCallDateComponents.day = 3
firstCellularPhoneCallDateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// "Apr 3, 1973, 12:00 AM"
let firstCellularPhoneCallDate = userCalendar.dateFromComponents(firstCellularPhoneCallDateComponents)!


// January 9, 2007, 18:00 UTC
let iPhoneAnnouncementDateComponents = NSDateComponents()
// We know that the "Stevenote" when the iPhone was announced
// started at 10:00 am Pacific time.
iPhoneAnnouncementDateComponents.year = 2007
iPhoneAnnouncementDateComponents.month = 1
iPhoneAnnouncementDateComponents.day = 9
iPhoneAnnouncementDateComponents.hour = 13
iPhoneAnnouncementDateComponents.minute = 0
iPhoneAnnouncementDateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// "Jan 9, 2007, 1:00 PM"
let iPhoneAnnouncementDate = userCalendar.dateFromComponents(iPhoneAnnouncementDateComponents)!


// January 27, 2010, 18:00 UTC
// We know that the "Stevenote" when the iPad was announced
// started at 10:00 am Pacific time.
let iPadAnnouncementDateComponents = NSDateComponents()
iPadAnnouncementDateComponents.year = 2010
iPadAnnouncementDateComponents.month = 1
iPadAnnouncementDateComponents.day = 27
// Let's set the clock using Pacific Time
iPadAnnouncementDateComponents.hour = 10
iPadAnnouncementDateComponents.minute = 0
iPadAnnouncementDateComponents.timeZone = NSTimeZone(name: "US/Pacific")
// On my system (US/Eastern time zone), the result for the line below is
// "Jan 27, 2010, 1:00 PM"
let iPadAnnouncementDate = userCalendar.dateFromComponents(iPadAnnouncementDateComponents)!

Note that we used different time zones for the “Stevenotes”. Both took place at the same time, 10:00 a.m. Pacific, but we set the time for the iPhone announcement as 1:00 p.m. US/Eastern, and the time for the iPad announcement as 10:00 a.m. US/Pacific. Both results in the sidebar appear at the same time; on my machine, they appear as Jan 27, 2010, 1:00 PM.

dateFromComponents works with what you give it

Suppose we want to create a date just by specifying that it’s 11:00 a.m. on the first Saturday of March 2015 in the US/Eastern time zone. Here’s how it’s done:

// (Previous code goes here)

// First Saturday of March 2015, US/Eastern
let firstSaturdayMarch2015DateComponents = NSDateComponents()
firstSaturdayMarch2015DateComponents.year = 2015
firstSaturdayMarch2015DateComponents.month = 3
firstSaturdayMarch2015DateComponents.weekday = 7
firstSaturdayMarch2015DateComponents.weekdayOrdinal = 1
firstSaturdayMarch2015DateComponents.hour = 11
firstSaturdayMarch2015DateComponents.minute = 0
firstSaturdayMarch2015DateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// "Mar 7, 2015, 11:00 AM"
let firstSaturdayMarch2015Date = userCalendar.dateFromComponents(firstSaturdayMarch2015DateComponents)!

NSDateComponentsweekday property lets you specify a weekday numerically. In Cocoa’s Gregorian calendar, the first day is Sunday, and is represented by the value 1. Monday is represented by 2, Tuesday is represented by 3, all the way to Saturday, which is represented by 7.

The weekdayOrdinal property lets you specify which specified weekday of the month. By setting weekday to 7, we’re specifying a Saturday; by then setting weekdayOrdinal to 1, we’re specifying the first Saturday of the month.

Here’s another example, where we get the date for the Thursday on the 18th week of 2015:

// (Previous code, including the definition of calendar,
// goes here)

// Thursday of the 18th week of 2015, US/Eastern
let thursday18thWeekOf2015DateComponents = NSDateComponents()
thursday18thWeekOf2015DateComponents.year = 2015
thursday18thWeekOf2015DateComponents.weekOfYear = 18
thursday18thWeekOf2015DateComponents.weekday = 5
thursday18thWeekOf2015DateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// ""Apr 30, 2015, 12:00 AM""
let thursday18thWeekOf2015Date = userCalendar.dateFromComponents(thursday18thWeekOf2015DateComponents)!

The other way around: getting NSDateComponents from NSDates

Right now, your playground should look like this, with a number of dates being created from date components:

// Playground - noun: a place where people can play

import UIKit

// The user's calendar incorporates the user's locale and
// time zones settings, so we'll often use it.
let userCalendar = NSCalendar.currentCalendar()


// March 10, 1876
// In this case, we're using an NSDatesComponents instance
// to represent a date rather than a duration of time.
let firstLandPhoneCallDateComponents = NSDateComponents()

// We don't know the time when Alexander Graham Bell made
// his historic phone call, so we'll simply provide the
// year, month and day. 
// We *do* know that he made that call in North America's
// eastern time zone, so we'll specify that.
firstLandPhoneCallDateComponents.year = 1876
firstLandPhoneCallDateComponents.month = 3
firstLandPhoneCallDateComponents.day = 10
firstLandPhoneCallDateComponents.timeZone = NSTimeZone(name: "US/Eastern")

// We have a calendar and date components. We can now make a date!
// On my system (US/Eastern time zone), the result for the line below is
// "Mar 10, 1876, 12:00 AM"
let firstLandPhoneCallDate = userCalendar.dateFromComponents(firstLandPhoneCallDateComponents)!


// April 3, 1973
let firstCellularPhoneCallDateComponents = NSDateComponents()
firstCellularPhoneCallDateComponents.year = 1973
firstCellularPhoneCallDateComponents.month = 4
firstCellularPhoneCallDateComponents.day = 3
firstCellularPhoneCallDateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// "Apr 3, 1973, 12:00 AM"
let firstCellularPhoneCallDate = userCalendar.dateFromComponents(firstCellularPhoneCallDateComponents)!


// January 9, 2007, 18:00 UTC
let iPhoneAnnouncementDateComponents = NSDateComponents()
// We know that the "Stevenote" when the iPhone was announced
// started at 10:00 am Pacific time.
iPhoneAnnouncementDateComponents.year = 2007
iPhoneAnnouncementDateComponents.month = 1
iPhoneAnnouncementDateComponents.day = 9
iPhoneAnnouncementDateComponents.hour = 13
iPhoneAnnouncementDateComponents.minute = 0
iPhoneAnnouncementDateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// "Jan 9, 2007, 1:00 PM"
let iPhoneAnnouncementDate = userCalendar.dateFromComponents(iPhoneAnnouncementDateComponents)!


// January 27, 2010, 18:00 UTC
// We know that the "Stevenote" when the iPad was announced
// started at 10:00 am Pacific time.
let iPadAnnouncementDateComponents = NSDateComponents()
iPadAnnouncementDateComponents.year = 2010
iPadAnnouncementDateComponents.month = 1
iPadAnnouncementDateComponents.day = 27
// Let's set the clock using Pacific Time
iPadAnnouncementDateComponents.hour = 10
iPadAnnouncementDateComponents.minute = 0
iPadAnnouncementDateComponents.timeZone = NSTimeZone(name: "US/Pacific")
// On my system (US/Eastern time zone), the result for the line below is
// "Jan 27, 2010, 1:00 PM"
let iPadAnnouncementDate = userCalendar.dateFromComponents(iPadAnnouncementDateComponents)!


// First Saturday of March 2015, US/Eastern
let firstSaturdayMarch2015DateComponents = NSDateComponents()
firstSaturdayMarch2015DateComponents.year = 2015
firstSaturdayMarch2015DateComponents.month = 3
firstSaturdayMarch2015DateComponents.weekday = 7
firstSaturdayMarch2015DateComponents.weekdayOrdinal = 1
firstSaturdayMarch2015DateComponents.hour = 11
firstSaturdayMarch2015DateComponents.minute = 0
firstSaturdayMarch2015DateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// "Mar 7, 2015, 11:00 AM"
let firstSaturdayMarch2015Date = userCalendar.dateFromComponents(firstSaturdayMarch2015DateComponents)!


// Thursday of the 18th week of 2015, US/Eastern
let thursday18thWeekOf2015DateComponents = NSDateComponents()
thursday18thWeekOf2015DateComponents.year = 2015
thursday18thWeekOf2015DateComponents.weekOfYear = 18
thursday18thWeekOf2015DateComponents.weekday = 5
thursday18thWeekOf2015DateComponents.timeZone = NSTimeZone(name: "US/Eastern")
// On my system (US/Eastern time zone), the result for the line below is
// "Apr 30, 2015, 12:00 AM"
let thursday18thWeekOf2015Date = userCalendar.dateFromComponents(thursday18thWeekOf2015DateComponents)!

Now it’s time to go the other way around, and extract date components from those dates. Once again, it’s the calendar that provides the method for making the conversion.

To extract NSDateComponents from an NSDate, we’ll do the following:

  • Create NSCalendar instances, if needed
  • Specify a set of date components using NSCalendarUnit bitmasks
  • Create the NSDateComponents by passing the NSDate instance to NSCalendar‘s components instance method

nsdate to nsdatecomponents

We already have a calendar instance: userCalendar, which is associated with the user’s time zone. If we use it to extract date components from a given date, the dates and times will be interpreted in the context of its time zone.

Let’s create two more calendars with two different time zones:

  • The US/Pacific time zone (UTC-08:00)
  • The Japan time zone (UTC+09:00)

Here’s what the code looks like:

// (Previous code goes here)

let pacificCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
pacificCalendar.timeZone = NSTimeZone(name: "US/Pacific")!

let japanCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
japanCalendar.timeZone = NSTimeZone(name: "Asia/Tokyo")!

Extracting all the possible date components from a date can be computationally costly, so NSCalendar‘s components instance method requires you to specify the components you want to extract. We want to extract these components from our dates:

  • year
  • month
  • day
  • hour
  • minute
  • weekday
  • weekdayOrdinal

Here’s the code that specifies this:

// (Previous code goes here)

let requestedDateComponents: NSCalendarUnit = [.Year,
                                               .Month,
                                               .Day,
                                               .Hour,
                                               .Minute,
                                               .Weekday,
                                               .WeekdayOrdinal]

Now that we’ve done that, we can start extracting date components:

// (Previous code goes here)

// Date components in the user's time zone
let jan9_2007Components = userCalendar.components(requestedDateComponents,
                                                  fromDate: iPhoneAnnouncementDate)
jan9_2007Components.year
jan9_2007Components.month
jan9_2007Components.day
jan9_2007Components.hour
jan9_2007Components.minute
jan9_2007Components.weekday
jan9_2007Components.weekdayOrdinal

// Date components in the US/Pacific time zone
let march10_1876PacificComponents = pacificCalendar.components(requestedDateComponents,
                                                               fromDate: iPhoneAnnouncementDate)
march10_1876PacificComponents.year
march10_1876PacificComponents.month
march10_1876PacificComponents.day
march10_1876PacificComponents.hour
march10_1876PacificComponents.minute
march10_1876PacificComponents.weekday
march10_1876PacificComponents.weekdayOrdinal

// Date components in Japan's time zone
let march10_1876JapanComponents = japanCalendar.components(requestedDateComponents,
                                                           fromDate: iPhoneAnnouncementDate)
march10_1876JapanComponents.year
march10_1876JapanComponents.month
march10_1876JapanComponents.day
march10_1876JapanComponents.hour
march10_1876JapanComponents.minute
march10_1876JapanComponents.weekday
march10_1876JapanComponents.weekdayOrdinal

In your playground’s sidebar, you should see results similar to those listed in the table below:

Component My user calendar Pacific calendar Japan calendar
year 2007 2007 2007
month 1 1 1
day 9 9 10
hour 13 10 3
minute 0 0 0
weekday 3 3 4
weekdayOrdinal 2 2 2

As you can see, January 9, 2007 at 10:00 a.m. in the US/Pacific time zone is January 9, 2007 at 1:00 p.m. in my time zone (US/Eastern) and January 10, 2007 at 3:00 a.m. in Japan. In the US, that date was the second Tuesday in January 2007; in Japan, it was the second Wednesday.

Turning dates into strings (and vice versa) with NSDateFormatter

nsdate - nsdateformatter - stringJust as you use an calendar to convert date components into dates and vice versa, you use a date formatter — an instance of the NSDateFormatter — to do the conversions.

Formatting date strings for the user

If you need to display a date as text for the user, it’s best if you use Cocoa’s built-in date styles. These are a set of predefined styles for formatting dates and times based on the user’s preferred settings. These styles, which are all values of the NSDateFormatterStyle enumeration, come in a selection of lengths — short, medium, long, and full — and using them is the preferred way to create date strings for the user to read.

Add the following code to your playground:

// (Previous code goes here)

let formatter = NSDateFormatter()

// No date style or time style defined:
// The result for the line below is
// ""
formatter.stringFromDate(firstLandPhoneCallDate)

// Only the date style is defined:
formatter.dateStyle = .MediumStyle
// The result for the line below is
// "Mar 10, 1876"
formatter.stringFromDate(firstLandPhoneCallDate)

// The date style and time style have been defined:
formatter.timeStyle = .ShortStyle
// The result for the line below is
// "Mar 10, 1876, 12:00 AM"
formatter.stringFromDate(firstLandPhoneCallDate)

Here’s how the various date and time formatter styles get rendered:

If dateStyle and timeStyle are both set to… the date formatter’s output looks like…
NoStyle
ShortStyle 1/27/10, 1:00 PM
MediumStyle Jan 27, 2010, 1:00:00 PM
LongStyle January 27, 2010 at 1:00:00 PM EST
FullStyle Wednesday, January 27, 2010 at 1:00:00 PM Eastern Standard Time

What’s up with NoStyle? It’s there so you can limit the resulting string so that it shows only the date or only the time.

NSDateFormatter has a timeZone property so that you can ensure that the date string reflects a specific time zone:

// (Previous code goes here)

formatter.dateStyle = .MediumStyle
formatter.timeStyle = .ShortStyle
formatter.timeZone = NSTimeZone(name: "US/Pacific")

// The result for the line below is
// "Jan 27, 2010, 10:00 AM"
formatter.stringFromDate(iPadAnnouncementDate)

Formatting date strings for other computers

As I wrote earlier, if you’re formatting dates for the user, it’s strongly recommended that you use NSDateFormatter‘s dateStyle and timeStyle properties, which will format dates and times according to the user’s settings. However, if you need to need your date strings to be in a specific format (for an API, for example), you can provide NSDateFormatter with a format string:

// (Previous code goes here)

// Setting the locale to POSIX ensures that
// the user's locale won't be used
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")

// NSDateFormatter's format string uses the date format specifiers
// spelled out in Unicode Technical Standard #35 (located at
// http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns)
formatter.dateFormat = "y-MM-dd"

// The result for the line below is
// "2007-01-09"
formatter.stringFromDate(iPhoneAnnouncementDate)

While you can browse through Appendix F of the Unicode Technical Standard #35 to look at all the date format specifiers supported by NSDateFormatter, you might find it easier to use the table below. It shows a number of format strings applied to the iPhone announcement date (January 9, 2007 at 10:00 a.m. Pacific):

Format string Result
'Year: 'y' Month: 'M' Day: 'd Year: 2007 Month: 1 Day: 9
MM/dd/yy 01/09/07
MMM dd, yyyy Jan 09, 2007
E MMM dd, yyyy Tue Jan 09, 2007
EEEE, MMMM dd, yyyy' at 'h:mm a. Tuesday, January 09, 2007 at 10:00 AM.
EEEE, MMMM dd, yyyy' at 'h:mm a zzzz. Tuesday, January 09, 2007 at 10:00 AM Pacific Standard Time.

Turning strings into dates

If you specify a date format string, you can use NSDateFormatter to take a string following that format to turn it into an NSDate. For example:

// (Previous code goes here)

formatter.dateFormat = "yyyy/MM/dd hh:mm Z"
// This string will be converted to a date because
// it's in the same format as the dateFormat string:
formatter.dateFromString("2015/03/07 11:00 -0500")!
// This string will NOT be converted to a date because
// it's NOT in the same format as the dateFormat string;
// its result will be nil:
formatter.dateFromString("Mar 7, 2015 11:00 AM EST")

// Let's change the date format strings and try
// dateFromString with the same two strings:
formatter.dateFormat = "MMM d, yyyy hh:mm a zz"
// This results in an NSDate:
formatter.dateFromString("Mar 7, 2015 11:00 AM EST")!
// This results in nil:
formatter.dateFromString("2014/11/05")

Tying it all together

If you’ve made it to this point in the article, this chart should now make sense:

cocoa date time class chart

Once again, click the chart to see it at full size.

You should now be able to:

  • Create dates “from scratch” (that is, create them using an offset of a number of  seconds from the start of the third millennium)
  • Create dates from date components (that is, from numbers representing a day, month, and year)
  • Convert between dates and date components
  • Convert dates into string representations and string representations of dates into dates

In the next article in this series, we’ll look at date calculations and some handy functions that let you harness Swift’s expressive power and make working with dates easier.

dates and times in swift - smallRelated articles

A very brief introduction to date formatting in Swift and iOS: The oversight in a mostly-good book on Swift programming led me down the path of writing articles about dates and times in Swift, starting with this one, where I look atNSDateFormatter.

How to work with dates and times in Swift, part two: Calculations with dates: Now that we’ve got the basics, it’s time to do some date arithmetic: comparing two dates to see which one is the earlier and later one, finding out how far apart two dates are, and adding and subtracting from dates.

How to work with dates and times in Swift, part three: Making date arithmetic more Swift-like: Cocoa’s date and time classes have an Objective-C heritage, which in the Swift context, feel kind of clunky. In this article, I look at ways — and by ways, I mean helper functions and class extensions — to make date calculations feel more like Swift.

How to work with dates and times in Swift, part four: A more Swift-like way to get the time interval between two dates: This quick article shows you how to make an operator overload that makes getting the time interval between two dates more like subtraction.

Categories
Uncategorized

iOS Fortnightly Tutorial: A Simple Weather App, Part 2

sorry were busyI know, I know, it’s been over a fortnight since I last post a tutorial. Things have been a little bit crazy at work, but I plan to hope to use the next couple of days to get caught up, and then post a new tutorial next week.

In the last installment, I posted another installment of my iOS development tutorial series, iOS Fortnightly: SimpleWeather, a simple weather app that made use of the AFNetworking library to fetch the current weather conditions for any given city from Open Weather Map. If you’d followed the tutorial to the end, you’d have an app that looks like this when immediately after you launch it:

…and here’s what it looks like when displaying the current weather:

It’s nowhere near ready for the App Store, but in a few lines of code, it accomplishes a fair bit. If you’re new to Objective-C, it also covers some unfamiliar territory. This week’s set of articles will expand on the Simple Weather app. In this one, I’ll explain those parts of the code that might not be familiar to the novice iOS developer, namely Objective-C’s blocks and properties.

JSON Requests in AFNetworking

AFNetworking logoThe meat of the SimpleWeather app is in the Weather class’ getCurrent: method. It makes the call to Open Weather Map’s API, and it does so with this line:

AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:weatherRequest
    success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        weatherServiceResponse = (NSDictionary *)JSON;
        [self parseWeatherServiceResponse];
    }
    failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        weatherServiceResponse = @{};
    }
];

AFJSONRequestOperation is a class in the AFNetworking library for requesting and retrieving JSON data from a given URL. It has a single method, a class method called JSONRequestOperationWithRequest:success:failure:. Here’s what its declaration looks like:

+ (AFJSONRequestOperation *)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest 
    success:(void ( ^ ) ( NSURLRequest *request, NSURLResponse *response, id JSON ))success
    failure:(void ( ^ ) ( NSURLRequest *request, NSURLResponse *response, NSError *error , id JSON ))failure

JSONRequestOperationWithRequest:success:failure: is a method that makes a request for some JSON from a given URL and:

  • Does something if the requested JSON was successfully received
  • Does something else if the requested JSON was not successfully received

Here are the method’s parameters:

Parameter Name Description
urlRequest A NSURLRequest object representing our request for the current weather from Open Weather Map.
success A function that should be executed if the operation was a success, meaning that the requested JSON object was successfully retrieved.
failure A function that should be executed if the operation was a failure. This could mean that requested JSON object was not successfully retrieved, or that it was successfully retrieved, but couldn’t be parsed as JSON.

The urlRequest argument is pretty straightforward, but the success and failure arguments look more complicated. They’re block literals, and to talk about them, we need to talk about blocks.

A Very Quick Intro to Objective-C’s Blocks

If you’re reasonably well-versed in JavaScript, it’s quite likely that you’re familiar with anonymous functions. Here’s a quick and dirty example: an anonymous function that takes two numbers and returns their sum, stored inside a variable named doSomething:

var doSomething = function(firstNumber, secondNumber)
{
  return firstNumber + secondNumber;
}
alert(doSomething(2, 3));

In Ruby, there are a couple of types of anonymous functions: procs and blocks. Procs are the anonymous function type that you can bind to a local variable, which is close to the spirit of anonymous functions in JavaScript and Objective-C. Here’s the Ruby version of the anonymous function from the example above:

doSomething = Proc.new {|firstNumber, secondNumber| firstNumber + secondNumber}
puts doSomething.call(2, 3)

And now, the Objective-C version:

int(^doSomething)(int, int) = ^(int firstNumber, int secondNumber) {
        return firstNumber + secondNumber;
    };
NSLog(@"%d", doSomething(2, 3));

It’s not all that different from the JavaScript and Ruby versions; it’s just that Objective-C requires explicit type information. Let’s take a look at the left side of the assignment first:

int(^doSomething)(int, int)

Here’s where cdecl comes in handy. It’s a site that translates declarations and casts from “C gibberish to English” and vice versa, comes in quite handy.

Enter int(^doSomething)(int, int) into cdecl. cdecl will translate it as “declare doSomething as block (int, int) returning int“. This in turn can be interpreted as “doSomething is a variable containing an anonymous function that takes two ints and returns an int“.

Now let’s look at the right side of the assignment:

^(int firstNumber, int secondNumber) {
        return firstNumber + secondNumber;
};

With the exception of the ^ character in front of the parameters, it looks like a like a standard function definition.

JSONRequestOperationWithRequest‘s Block Parameters, success and failure

Let’s look at JSONRequestOperationWithRequest‘s success parameter, which expects a block that should be executed if the JSON request operation is a success. Here’s its type:

(void ( ^ ) ( NSURLRequest *request, NSURLResponse *response, id JSON ))

This means that it expects a function that expects three parameters of type NSURLRequest *, NSURLResponse *, and id, and doesn’t return anything. Here’s what we’ll pass to it:

^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
    weatherServiceResponse = (NSDictionary *)JSON;
    [self parseWeatherServiceResponse];
}

It does two things:

  • It takes the retrieved JSON, casts it to NSDictionary *, and stores it in the instance variable (or, as they like to say in Objective-C, ivar) weatherServiceResponse. Note that the block “knows” about weatherServiceResponse
  • It calls the method parseWeatherServiceResponse, which extracts the data from the JSON retrieved from Open Weather Map and puts them into the instance variables behind the class’ properties.

Let’s now look at JSONRequestOperationWithRequest‘s failure parameter, which expects a block that should be executed if the JSON request operation is a failure. Here’s its type:

(void ( ^ ) ( NSURLRequest *request, NSURLResponse *response, NSError *error , id JSON ))

This means that it expects a function that expects four parameters of type NSURLRequest *, NSURLResponse *, NSError * and id, and doesn’t return anything. Here’s what we’ll pass to it:

^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
    weatherServiceResponse = @{};
}

Right now, we’re not worrying about what to do in the event of a failure, so for the moment, the failure block simply sets weatherServiceResponse to be an empty dictionary.

A Quick Look at Objective-C’s Properties and the Invisible Goodies that Come with Them

Consider the first line in the parseWeatherServiceResponse method:

_cloudCover = [weatherServiceResponse[@"clouds"][@"all"] integerValue];

If you look around the class, you’ll find that the variable _cloudCover hasn’t been declared anywhere. Yet Xcode hasn’t thrown up any error messages, and it colour-codes it as it would any declared variable. What’s going on here?

It turns out that there’s a little behind-the-scenes magic that takes place whenever a @property is declared. If you look in Weather.h, you’ll see this declaration:

@property (nonatomic, readonly) NSInteger cloudCover;

Implicit in this declaration is this corresponding line in the class’ .m file:

@synthesize cloudCover = _cloudCover;

This line doesn’t actually appear in the .m file, but it’s effectively there thanks to a little compiler magic. @synthesize itself does its own magic; it creates an invisible corresponding instance variable and invisible “getter” and “setter” methods. Implicit in the line above is this instance variable declaration:

NSInteger _cloudCover;

and these methods:

- (NSInteger)cloudCover {
    return _cloudCover;
}

- (void)setCloudCover:(BOOL)newValue {
    _cloudCover = newValue;
}

Property and ivar Order

Speaking of properties and ivars, take a look at the order of the ivars in parseWeatherServiceResponse, which lives in Weather.m:

- (void)parseWeatherServiceResponse
{
// clouds
_cloudCover = [weatherServiceResponse[@"clouds"][@"all"] integerValue];

// coord
_latitude = [weatherServiceResponse[@"coord"][@"lat"] doubleValue];
_longitude = [weatherServiceResponse[@"coord"][@"lon"] doubleValue];

// dt
_reportTime = [NSDate dateWithTimeIntervalSince1970:[weatherServiceResponse[@"dt"] doubleValue]];

// main
_humidity = [weatherServiceResponse[@"main"][@"humidity"] integerValue];
_pressure = [weatherServiceResponse[@"main"][@"pressure"] integerValue];
_tempCurrent = [Weather kelvinToCelsius:[weatherServiceResponse[@"main"][@"temp"] doubleValue]];
_tempMin = [Weather kelvinToCelsius:[weatherServiceResponse[@"main"][@"temp_min"] doubleValue]];
_tempMax = [Weather kelvinToCelsius:[weatherServiceResponse[@"main"][@"temp_max"] doubleValue]];

// name
_city = weatherServiceResponse[@"name"];

// rain
_rain3hours = [weatherServiceResponse[@"rain"][@"3h"] integerValue];

// snow
_snow3hours = [weatherServiceResponse[@"snow"][@"3h"] integerValue];

// sys
_country = weatherServiceResponse[@"sys"][@"country"];
_sunrise = [NSDate dateWithTimeIntervalSince1970:[weatherServiceResponse[@"sys"][@"sunrise"] doubleValue]];
_sunset = [NSDate dateWithTimeIntervalSince1970:[weatherServiceResponse[@"sys"][@"sunset"] doubleValue]];

// weather
_conditions = weatherServiceResponse[@"weather"];

// wind
_windDirection = [weatherServiceResponse[@"wind"][@"dir"] integerValue];
_windSpeed = [weatherServiceResponse[@"wind"][@"speed"] doubleValue];
}

In this method, I’m extracting data from the JSON objects returned by Open Weather Map, so they’re ordered from that perspective: by the keys of the top-level dictionaries in alphabetical order: clouds, coord, dt, main, name, rain, snow, sys, weather, wind. Those dictionaries’ elements are also listed in alphabetical order by key. The idea is to make things easy to find when programming with Open Weather Map’s API in mind.

The order of the corresponding @properties exposed in Weather.h is different. Here, I also want things to be easy to find, but I also want to abstract away any details about the format in which Open Weather Map returns its info. Instead, I want an order that’s useful for when you just want the weather, so I’ve used comments to break the properties into three groups: place and time, qualitative, and quantitative.

// Properties
// ==========

// Place and time
@property (nonatomic, copy, readonly) NSString *city;
@property (nonatomic, copy, readonly) NSString *country;
@property (nonatomic, readonly) CGFloat latitude;
@property (nonatomic, readonly) CGFloat longitude;
@property (nonatomic, copy, readonly) NSDate *reportTime;
@property (nonatomic, copy, readonly) NSDate *sunrise;
@property (nonatomic, copy, readonly) NSDate *sunset;

// Qualitative
@property (nonatomic, copy, readonly) NSArray *conditions;

// Quantitative
@property (nonatomic, readonly) NSInteger cloudCover;
@property (nonatomic, readonly) NSInteger humidity;
@property (nonatomic, readonly) NSInteger pressure;
@property (nonatomic, readonly) NSInteger rain3hours;
@property (nonatomic, readonly) NSInteger snow3hours;
@property (nonatomic, readonly) CGFloat tempCurrent;
@property (nonatomic, readonly) CGFloat tempMin;
@property (nonatomic, readonly) CGFloat tempMax;
@property (nonatomic, readonly) NSInteger windDirection;
@property (nonatomic, readonly) CGFloat windSpeed;

As with the ordering in parseWeatherServiceResponse, the objective is to make things easy to read and find, but this time, I’m doing so not from the perspective of a programmer trying to get data from the Open Weather Map API, but a programmer trying to get data from an instance of the Weather class.

Previous Installments in the iOS Fortnightly Series

In case you missed them, here’s a list of the previous articles in this series:

Categories
Uncategorized

iOS Fortnightly Tutorial: A Simple Weather App, Part 1

simpleweather running 4

Welcome to the second installment of iOS Fortnightly, Global Nerdy’s iOS programming tutorial series! If you’ve got a little experience with an object-oriented programming languages, whether it’s client-side JavaScript, server-side Perl, PHP, Python, or Ruby, or desktop Java, C#, or Visual Basic, this series is for you. Every fortnight — that’s a not-so-common word for “two weeks”, I’ll post a tutorial showing you how to write a simple but useful app that you can use as the launching point for your own iOS development projects. The idea behind iOS Fortnightly is to help you become familiar with mobile app development, the Objective-C programming language, the Cocoa Touch programming framework, and iOS application design.

ios fortnightly tutorials

In case you missed the previous iOS Fortnightly installment, go check it out. It’s a simple “Magic 8-Ball” app, but it’s the perfect starter app for someone who’s new to iOS development.

With the introduction out of the way, let’s move on to this fortnight’s app, a simple weather app. Let me start with what I think will be an iOS Fortnightly tradition — the video:

Question 1: Where Will the Weather Data Come From?

open weather map

I decided to go with Open Weather Map, a free-as-in-beer/free-as-in-speech weather data and forecast API in the spirit of Wikipedia and OpenStreetMap. While they recommend the use of a key to access the API (also free), it’s not absolutely necessary, which means that you can get started writing a weather app without having to sign up for an API key and waiting for approval. With a simple HTTP GET call, you can use it to get the current weather for a location that you can specify by:

  • City name,
  • Latitude and longitude, or
  • Numeric city ID

Here’s a sample call to Open Weather Map’s API for the current weather in my current location, Toronto, Canada:

http://api.openweathermap.org/data/2.5/weather?q=Toronto,CA

Here’s the resulting JSON object that came back when I wrote this article. Your results may vary, seeing as you’ll be making the call at a different day and time, but the format will be the same. It comes out as one long, continuous string; I’ve reformatted it so that it’s easier to read:

{"coord":{"lon":-79.416298,
          "lat":43.700111},
"sys":{"country":"CA",
       "sunrise":1378032138,
       "sunset":1378079546},
"weather":[{"id":701,
            "main":"Mist",
            "description":"mist",
            "icon":"50n"}],
"base":"gdps stations",
"main":{"temp":294.11,
        "humidity":93,
        "pressure":1009,
        "temp_min":292.59,
        "temp_max":295.15},
"wind":{"speed":1.3,
        "deg":187.501},
"rain":{"3h":0},
"clouds":{"all":0},
"dt":1378007487,
"id":6167865,
"name":"Toronto",
"cod":200}

Here’s a run-down of the returned object’s keys and values:

Element Description
cod The HTTP status code.
clouds The cloudiness, expressed as an object with a single key:

  • all: The cloud cover, expressed as a percentage (0 – 100).
coord The coordinates of the location for the weather report, expressed as an object with two keys:

  • lat: The location’s latitude, expressed in degrees (- is west, + is east)
  • lon: The location’s longitude, expressed in degrees (- is south, + is north)
dt Time the weather report was sent in the GMT time zone, expressed in Unix time.
main The quantitative weather, expressed as an object with these keys:

  • humidity: The humidity, expressed as a percentage (0 – 100).
  • pressure: The air pressure, in hectopascals (hundreds of pascals; 1 hectopascal is equal to one millibar).
  • temp: The current temperature, in degrees kelvin (1 degree kelvin = 1 degree celsius, 0 degrees C = 273.15 K).
  • temp_max: The predicted maximum temperature, in degrees kelvin.
  • temp_min: The predicted minimum temperature, in degrees kelvin.
name The name of the town or city closest to the location for the weather report.
rain The amount of rain expected to fall, expressed an object with this key:

  • 3h: Expected rainfall over the next 3 hours, in millimetres.
snow The amount of snow expected to fall, expressed as an object with this key:

  • 3h: Expected snowfall over the next 3 hours, in millimetres.
sys Other time and location data, expressed as an object with these keys:

  • country: The country in which the location for the weather report is located, expressed as an ISO two-letter country code.
  • sunrise: The time when sunrise will occur at the location for the weather report, expressed in Unix time.
  • sunset: The time when sunset will occur at the location for the weather report, expressed in Unix time.
weather The qualitative weather, expressed as an array containing one or more objects with the following keys:

  • description: A plain English description of the weather.
  • icon: The filename of the icon corresponding to the current weather. The full URL of the icon is http://openweathermap.org/img/w/filename.png.
  • id: The weather condition code, expressed as a three-digit number. See Open Weather Map’s “weather condition codes” page for an explanation of the codes.
wind The wind, expressed as an object with the following keys:

  • deg: Wind direction in meteorological degrees (0 is a north wind — that is, coming from the north, 90 is east, 180 is south, 270 is west).
  • speed: Wind speed in metres per second.

Question 2: How Will Open Weather Map’s Data be Accessed?

afnetworkingApple’s Cocoa Touch framework has its own class for downloading the contents of an URL — NSURLConnection — but we’ll use a third-party library that’s even simpler to use: AFNetworking, which describes itself as “a delightful networking framework for iOS and OSX” and is used at fine institutions such as Github, Heroku, and Pinterest.

Question 3: How Do We Include AFNetworking in an iOS Project?

cocoapodsAFNetworking can be manually included in a project, but I thought this would be a good opportunity to show the use of CocoaPods, the easy Ruby-based library dependency manager.

To install Cocoapods, fire up Terminal and type in the following lines:

$ sudo gem install cocoapods
$ pod setup

Create the Project

As with the previous project, we start with From the menu bar, choose File → New → Project…. You’ll see this:

single view application

Once again, this application will happen on a single screen, so we’ll go with a single-view application:

  • In the left column, under iOS, make sure that Application is selected.
  • In the big area on the right, select Single View Application.

Click Next to proceed to the next step:

choose options for project

On the “Choose options” screen…

  • Give your app a name by entering one into the Product Name field. I’m going with SimpleWeather.
  • Make sure that in the Devices menu, iPhone is selected.
  • Check the Use Storyboards checkbox.
  • Make sure that the Use Automatic Reference Counting checkbox is checked.

Click Next to proceed to the next step:

save project

Do this:

  • Choose the directory where your project will be saved. Your project will be saved in a directory inside the directory you chose.
  • Check the Create local git repository for this project checkbox. Git’s a good habit to get into, and there’ll come a time when being able to backtrack to a previous version of your code will save your bacon.
  • Make sure that the selection in the Add to: menu is Don’t add to any project or workspace.
  • Click the Create button.

So far, this isn’t all that different from the setup for the previous project. Here’s where it’s different — first, close the project. That’s right; close the project. We’re going to set up Cocoapods to bring AFNetworking into the project. Open the text editor of your choice and enter the following:

platform :ios, '6.0'
pod 'AFNetworking', '~> 1.3.2'

Save the file in your project directory. Double-check that it’s in the right place:

$ pwd
/Users/joey/Developer/iOS/Demo Apps/SimpleWeather
$ ls
Podfile			SimpleWeather		SimpleWeather.xcodeproj
$ cat Podfile
platform :ios, '6.0'
pod 'AFNetworking', '~> 1.3.2'

Once you’ve confirmed that the files are in the right place, install AFNetworking by entering pod install at the command line while in your project’s directory:

$ pod install
Analyzing dependencies
Downloading dependencies
Installing AFNetworking (1.3.2)
Generating Pods project
Integrating client project

[!] From now on use `SimpleWeather.xcworkspace`.

As the command-line output states, you should now open the project using SimpleWeather.xcworkspace, the full workspace file:

simpleweather.xcworkspace

Open the project by double-clicking on SimpleWeather.xcworkspace:

projects

If you look at the Project Navigator on the left side of Xcode’s window, you’ll see that the workspace is made up of two projects:

  • SimpleWeather, our weather app project, where we’ll be doing our work, and
  • Pods, which contains the AFNetworking code. We won’t touch it, but we’ll use its functionality to grab the weather info from Open Weather Map.

(If you want to find out more about workspaces, see this section of Apple’s documentation.)

Next step: drawing a quick user interface.

Draw the User Interface

In the Project Navigator on the left side of the Xcode window, select MainStoryboard.storyboard. Once again, we’re not going to bother with autolayout — we’re not quite at the fancy UI phase yet — so select the File Inspector on the right side of the window, and uncheck the Autolayout box:

screen 1

Click the screen capture to see it at full size.

Now to draw some controls on the view. In the Object Library, select Controls from the drop-down menu to narrow down the selection in the Object Library to just the UI controls. Drag the following from the Object Library onto the view:

  • A Label to a spot to near the top of the screen. Double-click it to edit its text, and change it to Where’s the weather in:.
  • A Text Field to just below the label, and stretch it to nearly the full width of the view.
  • A Round Rect Button to just below the text field. Double-click it to edit its text, and change it to Tell Me.

screen 2

Click the screen capture to see it at full size.

Connect the Controls to Code

First, let’s create an action for the Tell Me button:

  • Select the Assistant Editor so that both the storyboard and view controller header code in ViewController.h are both on display.
  • Select the Tell Me button, and then either right-click or control-click it. A grey window will pop up beside it, which will display actions and outlets.
  • Drag from the circle beside Touch Up Inside into the view controller header code, anywhere between @interface and @end.

screen 3

Click the screen capture to see it at full size.

In the little window that pops up:

  • Give the action a name. I used tellMeButtonPressed.
  • Make sure that the Event is Touch Up Inside.
  • Click the Connect button.

tellmebuttonpressed

You should now have the following line in the view controller header:

- (IBAction)tellMeButtonPressed:(id)sender;

First, let’s create an outlet for the text field:

  • Select the text field, and as we did with the button, right-click or control-click it. As with the button, a grey window will pop up beside it, which will display actions and outlets.
  • Drag from the circle beside New Referencing Outlet into the view controller header code, anywhere between @interface and @end.

screen 4

Click the screen capture to see it at full size.

locationtextField

In the little window that pops up:

  • Give the outlet a name. I used locationTextField.
  • Make sure that the Type is UITextField and that the Storage is Weak.
  • Click the Connect button.

You should now have the following line in the view controller header:

- (IBAction)tellMeButtonPressed:(id)sender;

With the action and outlet code inserted into the header, I did a little rearranging so that it looks like this:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

// Outlets
// =======
@property (weak, nonatomic) IBOutlet UITextField *locationTextField;

// Actions
// =======
- (IBAction)tellMeButtonPressed:(id)sender;

@end

Commit the Changes

Now’s a good time to commit the changes to git. Choose File → Source Control → Commit… from the menu bar. The “diffs” window will appear, which lets you see the changes you’re about to commit:

commit 1

Click the screen capture to see it at full size.

Enter a commit message — something like “Added controls and their actions and outlets”, then click the Commit 4 Files button to commit the changes.

Create a Model Class for the Weather Data

As I mentioned in the last article in the series, iOS apps are built on the Model-View-Controller pattern. Here’s how we’ll apply the pattern in this app:

simpleweather mvc

We’ve already got a view and view controller from the project setup work we’ve done — let’s create a model class. From the menu bar, File → New → File…. You’ll be presented with this dialog box:

Select Cocoa Touch from the sidebar on the left, then select Objective-C class, then click Next. You’ll see this:

create weather

Provide a name for the class. I gave mine the name Weather and made it a subclass of NSObject, the ultimate base class for every class in Objective-C. Once that’s done, click Next. You’ll be taken to the dialog box to save the class:

save class

Click Create to save the new class files. You can see them in the Project Navigator, marked with the letter A, denoting files that have been added since the last commit:

weather.h and weather.m

Now that we’ve got files for the Weather class’ interface (the header file, Weather.h) and implementation (the module file, Weather.m), let’s code! Let’s take care of the header first, where we specify the properties and methods that our model exposes:

Weather.h

#import <Foundation/Foundation.h>

@interface Weather : NSObject

// Properties
// ==========

// Place and time
@property (nonatomic, copy, readonly) NSString *city;
@property (nonatomic, copy, readonly) NSString *country;
@property (nonatomic, readonly) CGFloat latitude;
@property (nonatomic, readonly) CGFloat longitude;
@property (nonatomic, copy, readonly) NSDate *reportTime;
@property (nonatomic, copy, readonly) NSDate *sunrise;
@property (nonatomic, copy, readonly) NSDate *sunset;

// Qualitative
@property (nonatomic, copy, readonly) NSArray *conditions;

// Quantitative
@property (nonatomic, readonly) NSInteger cloudCover;
@property (nonatomic, readonly) NSInteger humidity;
@property (nonatomic, readonly) NSInteger pressure;
@property (nonatomic, readonly) NSInteger rain3hours;
@property (nonatomic, readonly) NSInteger snow3hours;
@property (nonatomic, readonly) CGFloat tempCurrent;
@property (nonatomic, readonly) CGFloat tempMin;
@property (nonatomic, readonly) CGFloat tempMax;
@property (nonatomic, readonly) NSInteger windDirection;
@property (nonatomic, readonly) CGFloat windSpeed;

// Methods
// =======

- (void)getCurrent:(NSString *)query;

@end

Note that what the model exposes is mostly properties and a single method, getCurrent. The idea is to call getCurrent with a query term, which can be a city name, a latitude/longitude pair, or a numeric city code. The model makes a call to Open Weather Maps using the query term, and uses the result to populate the model’s properties, which are then access by the view controller.

I’ll cover what all the @property stuff means in an article to follow.

Now that we have an interface, let’s code up the implementation:

Weather.m

#import "Weather.h"
#import "AFNetworking.h"

@implementation Weather {
    NSDictionary *weatherServiceResponse;
}

- (id)init
{
    self = [super init];

    weatherServiceResponse = @{};

    return self;
}

- (void)getCurrent:(NSString *)query
{
    NSString *const BASE_URL_STRING = @"http://api.openweathermap.org/data/2.5/weather";

    NSString *weatherURLText = [NSString stringWithFormat:@"%@?q=%@",
                                BASE_URL_STRING, query];
    NSURL *weatherURL = [NSURL URLWithString:weatherURLText];
    NSURLRequest *weatherRequest = [NSURLRequest requestWithURL:weatherURL];

    AFJSONRequestOperation *operation =
    [AFJSONRequestOperation JSONRequestOperationWithRequest:weatherRequest
                                                    success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
                                                        weatherServiceResponse = (NSDictionary *)JSON;
                                                        [self parseWeatherServiceResponse];
                                                    }
                                                    failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
                                                        weatherServiceResponse = @{};
                                                    }
     ];

    [operation start];
}

- (void)parseWeatherServiceResponse
{
    // clouds
    _cloudCover = [weatherServiceResponse[@"clouds"][@"all"] integerValue];

    // coord
    _latitude = [weatherServiceResponse[@"coord"][@"lat"] doubleValue];
    _longitude = [weatherServiceResponse[@"coord"][@"lon"] doubleValue];

    // dt
    _reportTime = [NSDate dateWithTimeIntervalSince1970:[weatherServiceResponse[@"dt"] doubleValue]];

    // main
    _humidity = [weatherServiceResponse[@"main"][@"humidity"] integerValue];
    _pressure = [weatherServiceResponse[@"main"][@"pressure"] integerValue];
    _tempCurrent = [Weather kelvinToCelsius:[weatherServiceResponse[@"main"][@"temp"] doubleValue]];
    _tempMin = [Weather kelvinToCelsius:[weatherServiceResponse[@"main"][@"temp_min"] doubleValue]];
    _tempMax = [Weather kelvinToCelsius:[weatherServiceResponse[@"main"][@"temp_max"] doubleValue]];

    // name
    _city = weatherServiceResponse[@"name"];

    // rain
    _rain3hours = [weatherServiceResponse[@"rain"][@"3h"] integerValue];

    // snow
    _snow3hours = [weatherServiceResponse[@"snow"][@"3h"] integerValue];

    // sys
    _country = weatherServiceResponse[@"sys"][@"country"];
    _sunrise = [NSDate dateWithTimeIntervalSince1970:[weatherServiceResponse[@"sys"][@"sunrise"] doubleValue]];
    _sunset = [NSDate dateWithTimeIntervalSince1970:[weatherServiceResponse[@"sys"][@"sunset"] doubleValue]];

    // weather
    _conditions = weatherServiceResponse[@"weather"];

    // wind
    _windDirection = [weatherServiceResponse[@"wind"][@"dir"] integerValue];
    _windSpeed = [weatherServiceResponse[@"wind"][@"speed"] doubleValue];
}

+ (double)kelvinToCelsius:(double)degreesKelvin
{
    const double ZERO_CELSIUS_IN_KELVIN = 273.15;
    return degreesKelvin - ZERO_CELSIUS_IN_KELVIN;
}

@end

As with the .h file, I’ll explain what’s in the .m file in an article to follow.

Connect the Model to the View Controller

We’ve got a functioning model, and a view controller connected to a view. It’s now time to make the final MVC connection: the one that links the model to the view controller. Change the code in ViewController.m to:

ViewContoller.m

#import "ViewController.h"
#import "Weather.h"

@interface ViewController ()

@end

@implementation ViewController {
    Weather *theWeather;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    theWeather = [[Weather alloc] init];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (IBAction)tellMeButtonPressed:(id)sender
{
    [theWeather getCurrent:self.locationTextField.text];

    NSString *report = [NSString stringWithFormat:
                        @"Weather in %@:\n"
                        @"%@\n"
                        @"Current temp.: %2.1f C\n"
                        @"High: %2.1f C\n"
                        @"Low: %2.1f C\n",
                        theWeather.city,
                        theWeather.conditions[0][@"description"],
                        theWeather.tempCurrent,
                        theWeather.tempMax,
                        theWeather.tempMin
                        ];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Current Weather"
                                                    message:report
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
}

@end

I’ll explain more about this code in a later article.

Run the App

We’ve got all the code we need for a working weather app. It won’t be slick, but it will work. When you run the app, you should see this:

simpleweather running 1

Enter the name of a city into the text field. In my case, I used my own city, Toronto, then tapped the Tell Me button:

simpleweather running 2

The first time you do this, you’ll most likely see a result like the one below. Don’t let it bother you for the time being:

simpleweather running 3

Don’t worry about this for now. I’ll explain why this happens in a follow-up article.

Dismiss the alert box by tapping the OK button, then tap the Tell Me button again. You should see some better results this time:

simpleweather running 4

That’s It for Now

Congratulations! You now have a working weather app. I’ll post a few follow-up articles featuring tweaks to the app, as well as explanations of the code behind it. In the meantime, commit your changes, and more importantly, play around with the code. Experiment. Tweak. Look up anything that seems odd, unfamilair or interesting!

If you have any questions or comments, or got stuck or encountered an error while doing this tutorial, let me know — either in the comments or by dropping me a line!

Categories
Uncategorized

iOS Fortnightly: Tweaking the 8-Ball App with a plist

ios fortnightly tutorials

On Monday, I posted the first of my fortnightly — that means “once every two weeks” — tutorials covering iOS development. If you’ve got some experience with an object-oriented programming language, and better still, any experience with an MVC application framework, these tutorials are for you!

The first tutorial covered a simple “Magic 8-Ball” app, where you’d tap a button, and it would display a randomly-selected answer to a “yes or no?” question. The program is pretty simple, and that’s a good thing — that way, it doesn’t get in the way of showing how to use Xcode, Objective-C, the various frameworks that make up Cocoa Touch, and so on.

While the main tutorials will appear every fortnight, from time to time, I’ll post supplementary articles in which I’ll expand on a topic covered in the tutorial or make an improvement to the app. This is one of those supplementary articles.

Defining the Answers

In the “8-ball” app created in the tutorial, the answers that the app can randomly choose from are defined in the model object’s constructor, shown below:

// DecisionMaker.m

// ... (other code here) ...

- (id)init
{
    self = [super init];
    answers = @[
                @"Yes.",
                @"No.",
                @"Sure, why not?",
                @"Ummm...maybe not.",
                @"I say \"Go for it!\"",
                @"I say \"Nuh-uh.\"",
                @"Mmmmmaybe.",
                @"Better not tell you now.",
                @"Why, yes!",
                @"The answer is \"NO!\"",
                @"Like I\'m going to tell you.",
                @"My cat\'s breath smells like cat food."
                ];
    return self;
}

// ... (other code here) ...

It works, but I get a little uncomfortable when hard-coding these sorts of values in this fashion. I’d much rather populate the array of answers by reading the contents of some kind of file or resource that isn’t part of the code. This approach typically makes the code more maintainable, as it makes the code less cluttered with data, and editing resource files is less likely to break something than editing code.

plists

plists, a.k.a. property lists, are XML files used in Mac OS and iOS to store data for things like initialization, settings, and configuration. Plists can hold the following types of scalar data:

  • boolean
  • data (binary data, that is)
  • date/time
  • number
  • string

Within a plist, any piece of data can sit on its own, or be organized into these collections:

  • array
  • dictionary (a.k.a. hash)

Here’s a quick plist example. It has a single array that contains the 1977 members of the Superfriends:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <string>Superman</string>
    <string>Batman and Robin</string>
    <string>Wonder Woman</string>
    <string>Aquaman</string>
    <string>Wonder Twins</string>
</array>
</plist>

Within Xcode, plists can be read and modified using a nice editor, which saves you the trouble of entering XML tags and lets you focus on the data instead.

In this exercise, we’re going to replace the 8-ball app’s hard-coded array of answers with a plist, and then initialize that array with the data in the plist.

Creating the plist of 8-Ball Answers

In the menu bar, select File → New → File…. You’ll see the following appear:

new plist file

In the left sidebar under the iOS section, select Resource. Then, from the main view, select Property List, then click Next. You’ll be taken to this dialog box:

answers.plist

Give the file a name in the Save As: text box; I named my file answers.plist. Click Create to save the plist to your project.

Filling the answers Array with the plist

Your Project Navigator should look something like this:

newly-created plist

Select the plist in the Project Navigator. The plist editor will appear in Xcode’s main pane. Use it to enter the 8-ball answers into the plist as shown below:

plist answers

Now that we’ve defined the plist, let’s change the constructor of the 8-Ball’s model, DecisionMaker, so that it reads the plist and feeds it into the answers array:

// DecisionMaker.m

- (id)init
{
    self = [super init];
    NSString *answersListPath = [[NSBundle mainBundle] pathForResource:@"answers"
                                                                ofType:@"plist"];
    answers = [NSArray arrayWithContentsOfFile:answersListPath];
    return self;
}

Let’s take a look at the new code line by line:

NSString *answersListPath = [[NSBundle mainBundle] pathForResource:@"answers"
                                                                ofType:@"plist"];

We need the list of answers, so we need to access answers.plist. It lives in the main bundle.

A bundle is a directory with a hierarchical structure that holds executable code and the resources used by that code. NSBundle is the class that handles bundles, and the mainBundle method returns the bundle that holds the app executable and its resources, which in the case of our 8-Ball app, includes answers.plist. The pathForResource:ofType: method, given the name of a resource and its type, returns the full pathname for that bundle.

Once we know the pathname for the bundle, we can construct the path to answers.plist, which is what the second line does.

answers = [NSArray arrayWithContentsOfFile:answersListPath];

arrayWithContentsOfFile is a handy method: given the path to a file containing a plist representation of an array, it will use the contents of a file to fill the array.

Run the App

The app is ready to go — fire it up, and it should look like this:

Reorganize the App…Just a Little

This is a small project, so it doesn’t have too many files. Even at this size, it’s good to keep its component files organized. Let’s put answers.plist into the Supporting Files folder, where the other resource files in the project live. Moving it is simply a matter of dragging and dropping in the Project Navigator, which should look something like this once you’ve moved answers.plist:

project navigator

Run the app again. It still works, even though answers.plist is in now in the Supporting Files folder, the folders are just a convenience for you, the developer, to organize files into manageable groups.

You’ve now got an app that loads its gets it answers from a plist rather than via a hard-coded array. You can even add new answers…

adding a new answer

Commit that Sucker!

At this point, it’s a good idea to commit this change to the repository. Call up File → Source Control → Commit… from the menu bar, enter an appropriate commit message (I used “Answers are now read from answers.plist instead of being hard-coded.”) and commit your changes. If you’re not in the habit of using source control, get into it now. It will save you a lot of pain.

Categories
Uncategorized

The First “iOS Fortnightly” Tutorial: The Magic 8-Ball

A Little Inspiration

jennifer dewalt

Jennifer Dewalt, burning the midnight oil.
Click the photo to see the source.

A couple of weeks back, I wrote about Jennifer Dewalt, who took on a big challenge. She had little or no programming education or experience but wanted to become a web developer, so she set out to learn  the hard way: by making “180 web sites in 180 days”. She put aside enough money to work on this project full-time in some space in San Francisco in a developer-rich workspace.

On Day 1 (April 1st), she made the homepage for her “180 sites” project in plain old HTML. Since then, she’s progressed and learning Ruby, Rails and JavaScript as she builds her apps. As of the evening of Sunday, August 18th, she’s on Day 140, with a web app that reports what your IP address is. You can see the master list of her projects on her project page, find out more as she chronicles her work on her blog, and get the source for all her projects from her GitHub account.

Dewalt’s determination, perserverance, and all-out chutzpah is admirable, and the way she framed her mission is quite clever. There’s nothing like a deadline to motivate you, and having to build a new project every day for six months forces you to constrain each one’s scope. The “build early, build often” approach also takes advantage of the idea behind the adage of “practice makes perfect”, which was put quite well in the book Art and Fear:

The ceramics teacher announced on opening day that he was dividing the class into two groups.

All those on the left side of the studio, he said, would be graded solely on the quantity of work they produced, all those on the right solely on its quality.

His procedure was simple: on the final day of class he would bring in his bathroom scales and weigh the work of the “quantity” group: 50 pounds of pots rated an “A”, 40 pounds a “B”, and so on.

Those being graded on “quality”, however, needed to produce only one pot — albeit a perfect one — to get an “A”.

Well, came grading time and a curious fact emerged: the works of highest quality were all produced by the group being graded for quantity.

It seems that while the “quantity” group was busily churning out piles of work-and learning from their mistakes — the “quality” group had sat theorizing about perfection, and in the end had little more to show for their efforts than grandiose theories and a pile of dead clay.

My Own “180 Days” Project

where the magic happens

My home office, pictured late Friday night.

I’ve decided to take up my own project along the same lines as Jennifer Dewalt’s. I’m going to publish an iOS development tutorial fortnightly — that is, once every two weeks — in which I walk the reader through the exercise of building a basic iPhone/iPad/iPod Touch app, explaining what I do along the way, and publish my code on my GitHub account.

I’m calling this series:

ios fortnightly tutorials

In order to follow along with iOS Fortnightly Tutorials, you’ll need some kind of Mac OS X computer that’s capable of running Xcode, the development tool. You’ll also need to get Xcode, which is available for free at the Mac App Store. It would help if you also had an iOS device and an iOS Developer account with Apple (you need one to deploy apps to iOS devices), but many of the projects in the tutorial will work just fine in the simulator.

These tutorials are best suited to people who’ve had some experience developing in any object-oriented programming language, from JavaScript to any of the standard suite of interpreted scripting languages (Perl, PHP, Python, or Ruby), or to compiled languages that often call for IDEs, such as C#, Java, or Visual Basic. Many of the principles that you’ve picked up in these languages will have some kind of analogue in Objective-C.

Unlike many tutorials, I’m not going to rehash what loops, and branches are, or explain what object-oriented programming is. I’ll explain stuff that would be new to someone just getting into Objective-C, Xcode, iOS, and Cocoa Touch‘s APIs. if you can’t quickly whip up FizzBuzz in the programming language of your choice, this programming tutorial series is probably not for you.

This Fortnight’s Tutorial: 8-Ball

magic 8-ball

If you grew up in North America, you’re probably familiar with the novelty item known as the Magic 8-Ball. You ask it a question that can be answered with “yes” or “no” and turn it over. A multi-sided die suspended in blue liquid rises to a clear window, revealing a random answer. If you haven’t ever tried on before, here’s an online version that’s been around for ages.

small inpulse

The Magic 8-Ball has been a staple of programming exercises since computer programming courses have existed. It’s also been a quick little programming exercise for learning how to program in new languages or on new platforms. I’ve even used it as a candidate in a job interview. When I talked to Pebble about becoming their developer evangelist over a two-day visit to Palo Alto last summer (yes, the smartwatch company that raise $10 million on Kickstarter), they tested me by making me write a tutorial for programming their previous smartwatch, the InPulse, and I chose the Magic 8-Ball as my example, which I posted on GitHub.

I figured that an iOS version of my Magic 8-Ball tutorial would be a good start, and if you’re new to iOS development, you might find it useful too!

Model – View – View Controller

model view view controller

Most programming frameworks for developing interactive applications are based on some variation of the MVC — that’s Model-View-Controller — pattern. The general idea is the interactive applications are the result of three categories of objects working together:

  • The model objects, which handle data and business logic,
  • The view objects, whose job is to present data to the user in the appropriate format, and
  • The controller objects, which take user requests and call on the other objects to carry them out.

iOS programming is generally based on the MVC pattern:

  • Models: You typically build your own custom model classes that represent that data and business logic for your app. Most of the time, these will be subclasses of NSObject, the class from which all Objective-C classes ultimately are derived.
  • Views: iOS provides UIView and a number of subclasses based on it — you can use these or subclass them.
  • Controllers: iOS provides UIViewController and a number of subclasses based on it — again, you can use these or subclass them. These are often referred to as view controllers.

If you’re comfortable with the concept of MVC, whether from client-side frameworks like Ember.js, or server-side frameworks like CakePHP, Django, or Rails, or from desktop app development, you’ll find the MVC aspect of iOS development familiar.

Time to get started!

Create a New Project

Let’s start with a new project. From the menu bar, choose FileNewProject…. You’ll see this:

choose a template

This first step is to specify what kind of project you’re building. Based on the selections you make, Xcode will pull together the appropriate frameworks and set up a basic code that will form the “skeleton” of your app.

Our “8-Ball” app is an iOS app where everything happens in a single screen or view, so we’ll make it a single-view app. Here’s how you specify this:

  • In the left column, under iOS, make sure that Application is selected.
  • In the big area on the right, select Single View Application.

Click Next to proceed to the next step:

choose options

The second step in creating a new app is to choose a few options. Here are the mandatory bits:

  • Give your app a name by entering one into the Product Name field. I gave mine the name 8Ball, but feel free to pick your own name.
  • Make sure that in the Devices menu, iPhone is selected.
  • Check the Use Storyboards checkbox. Storyboards are the newer interface-building metaphor for iOS apps. Using Storyboards is an option with the current version of Xcode, but it’s the default in the upcoming Xcode 5, so it’s best to get used to them now. Since this is a single-screen app, there isn’t much of a difference between storyboards and “the old way”.
  • Make sure that the Use Automatic Reference Counting checkbox is checked. Once again, don’t worry about what this means right now.

Xcode automatically fills in the Organization Name and Company Identifier fields based on the business name from the “Me” entry in your Mac’s Address Book application. For now, go with these; at this point, they’re not important.

Pick a Location to Save the Project

Click Next to proceed to the next step:

where to save

In this step, do this:

  • Choose the directory where your project will be saved. Your project will be saved in a directory inside the directory you chose.
  • Check the Create local git repository for this project checkbox. Unlike most iOS tutorials, this one will also talk about using version control with Git from within Xcode.
  • Make sure that the selection in the Add to: menu is Don’t add to any project or workspace.

At this point, Xcode has enough information to create a new project. Click the Create button; Xcode will get to work and after a moment or two, you’ll have a project. You’ll be taken to Xcode’s main window, which will look something like this:

fresh project

An Overview of Xcode’s User Interface

Before we get coding, let’s take a quick look at the five major parts of Xcode’s user interface:

xcode user interface

If you’ve worked with other IDEs, such as Visual Studio or Eclipse, Xcode’s layout should be familiar to you. Its main window has these five sections:

  1. Toolbar: Located at the top of Xcode’s main window, this iTunes-esque  part of Xcode’s user interface is the home of a number of often-used controls, including those for running and debugging apps, and customizing Xcode’s UI.
  2. Navigators: These occupy the whole left sidebar. As their name implies, they’re used to navigate around projects. It has a number of tabs, the leftmost one being the Project Navigator (it has a file folder icon), which lets you navigate the files that make up your project.
  3. Main View: This is where you’ll do most of your work, including coding.
  4. Inspectors: These occupy the top portion of the right sidebar, and they’re used to view and edit the properties of  is the sidebar on the right, and it’s used to view and edit the properties of code and UI elements. Like the navigators, the set of inspectors has a tabbed interface that lets you select an inspector.
  5. Libraries: The libraries are collections of things that you’ll find useful for coding: code templates, code snippets, and UI and media objects.

A Peek at the Repository

You can look at the local git repository that was created along with the project by opening the Organizer. The button to view it is located near the upper right-hand corner of Xcode’s main window:

organizer

Once the Organizer window has opened, click on the Repositories button on its toolbar. You should see a window similar to this one:

organizer 1

Notice that the first commit has been automatically made for you. If you click on the disclosure triangle for your first commit, you’ll get a list of all the files in your project, each marked with an “A” on the left. That’s “A” as in Git’s file status flag for files that have just been Added:

organizer 2

If you click the View Changes button, you’ll be presented with a window that lets you view the diffs for any of the files that were committed:

view changes

The “after” pane is the one on the left, and the “before” pane is the one on the right. Since this is our first and only commit so far, the files were newly-added, and thus the “befores” and “afters” are the same.

If you feel like doing a little double-checking on the command, feel free to open a terminal window, go to your project’s directory, and do a git status.

Take the Project for a Test Run

Even though we haven’t put any code into the project yet, it never hurts to take it for a test run. The controls for doing so are by the upper left-hand corner:

toolbar run controls

Make sure that iPhone 6.1 Simulator is selected in the Scheme menu, then hit the Run button. The simulator will spin up, and you should see something like this:

empty running app

Now that we’ve got a working new empty project and a local repository, let’s start coding!

Draw the View

Take a look at the left sidebar, where the navigators live, and make sure the Project Navigator (select it with the leftmost icon, the file folder) is the currently visible one. Select MainStoryboard.storyboard in the Project Navigator:

proj navigato

Xcode should look like this:

main storyboard

We’re going to do is disable Autolayout for this project. Autolayout is a feature that allows a user interface to adjust itself to various screen orientations (portrait and landscape) as well as screen sizes (which vary among iPhone and iPad models). While it’s useful, it adds a degree of complexity that we don’t want to deal with in these first few tutorials.

To turn off Autolayout, select the view as shown below. Then make sure that the File Inspector (the inspectors are in the upper part of Xcode’s right sidebar; the file inspector is the one with the document icon) is selected, then uncheck the Use Autolayout checkbox:

autolayout

The libraries are also located in the right sidebar, just below the inspectors. We want to put a couple of controls onto the view:

  • label, which will be used to display the 8-ball’s answers, and
  • a button that the user presses to get a new answer.

UI controls live in the Object Library (the one with the box icon). Make sure it’s selected, then select Controls from the drop-down menu to filter the list so that only UI controls appear:

obj library

Drag a button from the Object Library to the center of the view, then drag a label from the Object Library to a spot just above the button:

drag controls

Xcode’s user interface drawing tools have guides that “auto-magically” appear to help you lay them out. They’ll help you position controls relative to the position of other controls, and help you center the label and button relative to each other.

Widen the button the little, and stretch the label so that it’s almost as wide as the entire view. Use the guides to help you determine how wide you should stretch the label:

make label and button wider

If you run the app now, it’ll look like this:

app with label and button

The button switches to its highlighted state when you press it, and it stays that way as long as your finger’s on it:

app with label and button 2

It doesn’t do much yet, but it’s a functioning view. The next step is to set up the view controller.

But First, a Quick Peek at Our Files

Before we get to the view controller, let’s take a look at the Project Navigator. There’s something new beside the MainStoryboard.storyboard file:

modified file state

The M is one of Git’s file states, and it denotes that the file’s been modified since the last commit to the local repository. This will happen as you make changes to files in your project’s directory.

Set Up the View Controller with an Outlet and an Action

Now that we’ve got a view with a label and a button, we want to do the following with them:

  • Label: We want to be able to change its text.
  • Button: We want to know when the user has pressed it.

Let’s take care of the label first.

Create an Outlet for the Label

Right now, there’s no way for any code you write to refer to the label that you added to the view. You need to create an outlet, which gives you an object that you can use to refer to an control on the storyboard. Once you have an outlet for a control, you can access that control, call its methods and get and set its properties.

We need to get both the storyboard and the view controller’s header onscreen at the same time. Luckily, the Assistant Editor (its button is pictured below) can help:

assistant editor button

The Assistant editor was designed to help with the sort of bouncing about between related files that often happens when working on Objective-C projects. You’ll often find yourself bouncing between a class or module’s .h file (its interface) and its .m file (its implementation), and between a view on the storyboard and its corresponding .h file. The Assistant Editor, when you call it up, considers the last thing you were editing, and opens the related file.

Make sure that the storyboard is in the main view (it should, if you’ve been following this tutorial so far). Click the Assistant Editor button…

outlet 1

…and a text editor for the view controller’s header file will appear. Depending on your Xcode setup, the header file will appear in a pane that will appear either beside or underneath the storyboard.

To make the connection, you’ll need to make use of the Connection Inspector, one of the inspectors available in the right sidebar. Make sure that the label is selected in the storyboard, click the Connection Inspector button (the one with the “arrow in circle” icon), and look for an item marked New Referencing Outlet. There’s a circle to its right; drag from that circle to anywhere inside the view controller’s header file that’s between @interface and @end:
outlet 2

When you complete the drag, a little pop-up will appear:

outlet 3

Provide a name for the outlet in the Name text field. I used answerLabel. Click the Connect button. The code in the header file should now be:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *answerLabel;

@end

What is @property?

A common practice in many object-oriented languages is to keep a class’ instance variables private and grant access to them via “getters” and “setters” or accessor methods. In Java, following this practice means that you have to do everything yourself: create an instance variable, then define public getter and setter methods that allow outside code to read and write the value in that instance variable.

Objective-C’s @property directive automates this process, telling the compiler to generate the following:

  • A hidden ivar (Objective-C jargon for “instance variable”) where the value for the property will be stored. The ivar’s name is simply the name of the property preceded by an underscore (_) character. The ivar’s type will be the same as the property’s. In the case of our answerLabel property, the hidden ivar that will be created is _answerLabel, and its type is UILabel.
  • A hidden getter method, whose name and type is the same as the property. In the case of our  answerLabel property, the getter’s name is  answerLabel, and its type is UILabel.
  • A hidden setter method, whose name and type is the same as the property. In the case of our answerLabel property, the setter’s name is  answerLabel, and its type is UILabel.

If you develop in C#, its properties are similar to Objective-C’s properties. If you develop in Ruby, Objective-C’s properties aren’t too different from using attr_accessor.

Let’s take a closer look at the line that just got added to the view controller’s header:

@property (weak, nonatomic) IBOutlet UILabel *answerLabel;

Here’s what each part means:

  • @property: Indicates that we’re defining a property.
  • (weak, nonatomic): The @property keyword is usually followed by a number of modifiers in parentheses. In this case, the two modifiers are:
    • weak: This is one of the possible memory management modifiers for properties: in addition to weak, there’s strong, assign, and copy. I’ll cover this in more detail in a later article. For now, you should note that weak is the preferred modifier for outlets.
    • nonatomic: This is one of the possible concurrency modifiers: in addition to nonatomic, there’s atomic. These modifiers specify how properties behave in an environment with threading; by specifying that a property is atomic, you can ensure that the underlying object is locked when its getter or setter is called, thereby preventing threaded code from messing it up. For apps that don’t make use of threading (or if you’ve rolled your own thread-safety mechanism), the general rule is to define your classes’ properties as nonatomic.
  • IBOutlet: A dummy keyword that has no effect on your code. It’s there for the benefit of Xcode’s interface builder (which is why it’s prefixed with IB), so that it knows that this property is an outlet.
  • UILabel *: The type of our property. UILabel is iOS’s class for label controls. If you’re new to C or Objective-C, the * tells you that this property is a pointer to an object of type UILabel.
  • answerLabel: The name of our property.

Now that we have an outlet named answerLabel that’s a property of the view controller, we can now refer to the label in code simply by using self.answerLabel.

Create an Action for the Button

We also need some way for our code to be notified when the user presses the button. That way is an action — a method that gets called in response to an event. Creating an action is pretty similar to creating an outlet.

Select the button, then make the Connections Inspector the active one. A list will appear in the right sidebar:

action 1

Take a look at the section of the list marked Sent Events. This lists the events that the button can respond to. We’re interested in the Touch Up Inside event, which happens when the user presses on the button, then releases it while his/her finger is still within the bounds of the button. It’s the event that corresponds to a regular button press, so it’s the one we want to respond to.

Creating an action is similar to creating an outlet — you create one by selecting an event and connecting it dragging it to the view controller’s hear file. Make sure that the button is selected in the storyboard and that the Connection Inspector is active. Drag from the circle beside Touch Up Inside to anywhere inside the view controller’s header file that’s between @interface and @end:

action 3When you complete the drag, a little pop-up will appear:

action 4

Do the following:

  • Provide a name for the action in the Name text field. I used answerButtonPressed.
  • Change the Type from the default value of id (Objective-C’s type that means “pointer to any object”) to UIButton. The action will work just fine with id, but I prefer to be as type-specific as possible.

Click the Connect button. The code in the header file should now be:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *answerLabel;
- (IBAction)answerButtonPressed:(UIButton *)sender;

@end

Let’s take a closer look at the line that just got added to the view controller’s header:

- (IBAction)answerButtonPressed:(UIButton *)sender;

It’s the signature for a method. Here’s what each part means:

  • -: The - means that this method is an instance method as opposed to a class method.
  • (IBAction): This is the return type of the method. IBAction is #defined to be a synonym for void. It’s there for the benefit of Xcode’s interface builder (which is why it’s prefixed with IB), so that it knows that this property is an action.
  • answerButtonPressed: the name of the method.
  • (UIButton *)sender: sender is the name of the single parameter this method takes, and its type is UIButton *, a pointer to object of type UIButton.

Adding the action put the interface for its method in the view controller’s header file, but that’s not the only file that changed. If you look at the view controller’s module or implementation file (ViewController.m), you’ll notice that the implementation for the method was placed there. It’s an empty method and looks like this:

- (IBAction)answerButtonPressed:(UIButton *)sender {
}

Let’s Use That Outlet and Action!

We now have an outlet for the label and an action for the button. We can now write some code to respond to button presses by changing the text inside the label. Change the implementation of answerButtonPressed in ViewController.m by adding a line:

- (IBAction)answerButtonPressed:(UIButton *)sender {
    self.answerLabel.text = @"You pressed the button!";
}

In this one method, we’re using:

  • The action, answerButtonPressed, to respond to the user pressing the button, and
  • the outlet, answerLabel, to change the text of the label.

Note the @ in the line:

    self.answerLabel.text = @"You pressed the button!";

When you put text in quotes preceded by the @ sign, you’re using Objective-C shorthand for “create an NSString object containing this text. NSString is the string class for work in Objective-C, and it has a whole lot of useful features including Unicode support. Without the @, you’re creating a plain old C string, which isn’t an object type, but a simple zero-terminated C array of ASCII characters.

If you run the app in the simulator now, you’ll see this at the start:

app with label and button

But after you press the button, it’ll look like this:

you pressed the button

Let’s make one more change. Right now, when you run the app, the label and button still contain their default text at the beginning. Let’s change their text to something more suitable.

There are two ways to change the initial contents of the label and button. One way is to use Xcode’s interface builder and make the changes in the storyboard. This is as simple as double-clicking on the label or button, which puts them in a mode that lets you edit their text. I find that this is fine for quick-and-dirty projects and hashing out prototypes.

The other way is to set the contents of the label and button in code. Every view has a method named viewDidLoad, which gets called immediately after the view is loaded into memory, but before it’s displayed. It’s an excellent time to run all sorts of initialization code, including doing all sorts of user interface configuration. I think that this is the more maintainable approach, and it’s the approach we’ll use.

In order to be able to set the button’s content in code, we’ll need to create an outlet for it. This is a good excuse to show you another way to create an outlet. With both the storyboard and the header file for the view controller visible, right-click on the button. A pop-up containing the same items as the Connection Inspector will appear. Drag a connection from New Referencing Outlet to the code in the header, as shown below:

button outlet

Another pop-up will appear:

answerbutton

Provide a name for the outlet in the Name text field. I used answerButton. If the Type property isn’t already set that way, change it to UIButton. Click the Connect button. The code in the header file should now be:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *answerLabel;
- (IBAction)answerButtonPressed:(UIButton *)sender;
@property (weak, nonatomic) IBOutlet UIButton *answerButton;

@end

I prefer to put my header files’ @property and IBAction declarations into their own groups, so I’ve rearranged my view controller’s header file to look like this:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *answerLabel;
@property (weak, nonatomic) IBOutlet UIButton *answerButton;

- (IBAction)answerButtonPressed:(UIButton *)sender;

@end

Now that we have an outlet for the button as well as the label, we can now write some initialization code for both of them. Go to the top of the view controller’s implementation file, ViewController.m. You’ll find the viewDidLoad method’s implementation there. It looks like this:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

Change viewDidLoad to:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Initialize the UI
    // -----------------
    self.answerLabel.text = @"Need an answer? Hit the button!";
    self.answerLabel.textAlignment = NSTextAlignmentCenter;

    [self.answerButton setTitle:@"Get an answer" forState:UIControlStateNormal];
    [self.answerButton setTitle:@"Thinking..." forState:UIControlStateHighlighted];
}

Let’s examine these a control at a time:

    self.answerLabel.text = @"Need an answer? Hit the button!";
    self.answerLabel.textAlignment = NSTextAlignmentCenter;

You’ve probably already figured out what this one does: it sets the initial text of the label to Need an answer? Hit the button!, and then sets the label’s contents to be center-aligned.

Here’s the button code:

    [self.answerButton setTitle:@"Get an answer" forState:UIControlStateNormal];
    [self.answerButton setTitle:@"Thinking..." forState:UIControlStateHighlighted];

If you’re new to Objective-C, you might find its method-calling syntax odd. Method calls in Objective-C are like this:

[objectName methodName]

In Objective-C parameters become part of the method name. For example, let’s suppose that you were to call a on an object of type Person that set the person’s first and last names. In many popular object-oriented programming languages, the method call to set a Person object’s names to “Tony Stark” would look like this:

somePerson.setName("Tony", "Stark");

In Objective-C, the method call would look like this:

[somePerson setFirstName:@"Tony" lastName:@"Stark"];

…and the proper name for the method would be setFirstName:lastName.

Unlike labels, whose content can be set simply by accessing their text property, you need to call a method to set the text of a button: setTitle:forState:. We use this method twice, once for each of these states:

  • The normal state, when the button is not being pressed.
  • The highlighted state, when the button is being pressed.

If you the app now, it’ll look like this at startup:

workingbuttonandlabel3

If you press and hold the button, it’ll look like this:

workingbuttonandlabel2

And when you release the button, it’ll look like this:

workingbuttonandlabel1

This looks like a good time commit these changes to the Git repository.

Committing Our Changes

If you look at the Project Navigator (in the left sidebar), you should see this:

modified files

MainStoryboard.storyboard, ViewController.h, and ViewController.m have all been modified, and they’re marked with an M. We want to commit these changes, so fire up the source control by going to the menu bar and choosing File → Source Control → Commit…:

commit

You’ll be taken to a screen where you can review the changes before committing them:

git diff

Click on MainStoryboard.storyboardViewController.h, and ViewController.m in the sidebar on the left to see the difference between the current versions of these files and the versions from the time they were last committed to the repository. Once you’re satisfied with the changes:

  • Enter a commit message in the field at the bottom of the window. I entered “Added button and label, outlets and an action for them, and some basic test code.”
  • Click the Commit 3 Files button.

Let’s confirm that the changes were committed. Open the Organizer (once again, you do this by clicking on the Organizer button near the upper right-hand corner of Xcode’s window:

organizer

When the Organizer window appears, click the Repositories button. You’ll see the list of commits again, but this time there are two:

  • The initial commit automatically generated when you created the project, and
  • the commit we just made.

2 commits

Finally: Code Up the Model

All that remains is to write the code to generate random answers for the 8-Ball. This is simple enough to stick into the view controller, but let’s do it the right way and code up a proper model object. We’ll create a model class that will house the random answer generator.

Let’s create a new class. From the menu bar, File → New → File…. You’ll be presented with this dialog box:

new class

Do as the picture above says. Select Cocoa Touch from the sidebar on the left, then select Objective-C class, then click Next. You’ll then see this:

decisionmaker

Provide a name for the class — I named it DecisionMaker — and make it a subclass of NSObject, the ultimate base class for every class in Objective-C. Once that’s done, click Next. You’ll see this:

directory

Click Create to save the new class files. You can see them in the Project Navigator, marked with the letter A, denoting files that have been added since the last commit:

added files

Xcode will automatically open text editors for the header and implementation files for the newly-created class, DecisionMaker.h and DecisionMaker.m:

decisionmaker h and m

Time to start coding! First, the let’s write the code for the DecisionMaker class’ header file, DecisionMaker.h:

#import <Foundation/Foundation.h>

@interface DecisionMaker : NSObject

- (NSString *)getRandomAnswer;

@end

Right now, DecisionMaker will expose a single method called getRandomAnswer, so we need to put its signature into the header file. getRandomAnswer doesn’t take any arguments, but does return a string.

Now for the implementation:

#import "DecisionMaker.h"

@implementation DecisionMaker {
    NSArray *answers;
}

- (id)init
{
    self = [super init];
    answers = @[
                @"Yes.",
                @"No.",
                @"Sure, why not?",
                @"Ummm...maybe not.",
                @"I say \"Go for it!\"",
                @"I say \"Nuh-uh.\"",
                @"Mmmmmaybe.",
                @"Better not tell you now.",
                @"Why, yes!",
                @"The answer is \"NO!\"",
                @"Like I\'m going to tell you.",
                @"My cat\'s breath smells like cat food."
                ];
    return self;
}

- (NSString *)getRandomAnswer
{
    return answers[arc4random() % answers.count];
}

@end

Here’s what you should note from the code above:

  • Instance variables — or ivars, as many Objective-C developers like to call them — go into a block immediately after the @implementation line. This class has a single ivar, answers, which is an NSArray that will hold the answers to randomly choose from. In Objective-C programming, NSArrays are generally favoured over straight-up C arrays.
  • There are two methods in this class:
    • init: This is the constructor, where in addition to constructing instances of the class, the array of answers is initialized.
    • getRandomAnswer, which produces the 8-Ball’s answers.
  • arc4random() is a pseudo-random number generator that’s part of the standard C library and is considered to be the go-to random number generator for general random number needs. It has a decent randomization algorithm and generates pseudorandom numbers between 0 and  2^32 – 1 (which is about 4.3 billion). To get a pseudorandom number between 0 and n, use arc4random() % n.

With the model done, it’s time to go back to the view controller’s implementation file, ViewController.m, to make use of it:

#import "ViewController.h"
#import "DecisionMaker.h"

@interface ViewController ()

@end

@implementation ViewController {
    DecisionMaker *answerSource;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Initialize the UI
    // -----------------
    self.answerLabel.text = @"Need an answer? Hit the button!";
    self.answerLabel.textAlignment = NSTextAlignmentCenter;

    [self.answerButton setTitle:@"Get an answer" forState:UIControlStateNormal];
    [self.answerButton setTitle:@"Thinking..." forState:UIControlStateHighlighted];

    // Initialize the decision maker
    // -----------------------------
    answerSource = [[DecisionMaker alloc] init];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)answerButtonPressed:(UIButton *)sender {
    self.answerLabel.text = [answerSource getRandomAnswer];
}
@end

Here’s what’s happening in this code:

  • Once again, instance variables — ahem, ivars — go into a block immediately after the @implementation line. We’ve added a single ivar, answerSource, which is our model.
  • We initialize answerSource in the viewDidLoad method. Since it’s executed just after the view is loaded but before it’s drawn, it’s a good place to do initializing.
  • We changed the code in the answerButtonPressed action to set the label’s text to a randomly-selected answer provided by answerSource.

Here’s what the app looks like when you run it:

smells like cat food

Commit the Changes

With a functioning model added, it’s a good time to commit the changes. Go to menu bar and choose File → Source Control → Commit… and commit those changes!

Follow-up Article

Be sure to take a look at the follow-up article, Tweaking the 8-Ball App with a plist, where we make use of property lists, a.k.a. plists, a useful feature. This subtle change to the code makes it easier to maintain.

Next Steps

This is a simple project, and you should feel free to expand upon it or build new projects using this one as a basis. Some other exercises you might want to try include:

  • Turning this app into a game of chance, or a dice-roller for role-playing games
  • Building an iOS equivalent of those party games made up of a deck of cards containing interesting “get to know the real you” questions
  • Fixing up the user interface to make it either incredibly skeuomorphic as a number of iOS apps are, or give it the really clean look of the upcoming iOS 7
  • Changing the app so that the answers aren’t hard-coded into the DecisionMaker model, but perhaps read from a resource file or even an online file
Categories
Uncategorized

Learn Windows Phone 7 with the “Jump Start” Course

Andy Wigley and Rob Miles: "Live from inside the TARDIS, it's the Windows Phone 7 Jump Start Course!"

(Well, it’s two English guys surrounded by tech gear and a psychedelic background. The interior of the TARDIS came to mind.)

The Windows Phone 7 Jump Start is the first of a number of free online courses on WP7 programming led by Microsoft MVPs, and you can jump in right now! Presented by Andy Wigley and Rob Miles, the Jump Start is made up of 12 50-minute videos for a total of ten hours’ worth of training, covering development of both Silverlight- and XNA-based apps as well as advanced topics such as the WP7 application lifecycle, launchers, choosers, isolated storage, taking advantage of the dialer, camera and contacts, and networking. There’s even a section on bringing your app over to the Marketplace. It’s all online, free and ready for you to dive in!

The videos in the course are:

  1. Introduction
  2. Building a Silverlight Application, Part 1
  3. Building a Silverlight Application, Part 2
  4. Building Games for the Windows Phone 7 Platform
  5. Building XNA Games for the Windows Phone 7 Platform, Part 1
  6. Building XNA Games for the Windows Phone 7 Platform, Part 2
  7. Advanced Application Development, Part 1
  8. Advanced Application Development, Part 2
  9. Advanced Application Development, Part 3
  10. Marketing Your Windows Phone 7 Application
  11. Working with Media
  12. Final Silverlight Topics and Wrap-Up

You can watch the videos on their pages (Silverlight required) or download them in WMA, WMV and MP4 formats for offline viewing.

This article also appears in Canadian Developer Connection.

Categories
Uncategorized

Casual Cryptography for Web Developers

The article Casual Cryptography for Web Developers is probably the nicest, most concise explanation of some of the important crypto principles and practices that web developers will need. Whether you are new to web development, need a refresher or are just curious about the fundamentals, this is one of the best starter articles I’ve seen.