In this series, you learn how to build a weather application for iOS with Swift 3. Along the way, you learn several skills that are essential for iOS development, including:
- Creating an Application With Xcode and Swift 3
- Fetching Data From a Web Service
- Testing Your Application
- Creating User Interfaces With Storyboards and Auto Layout
- Putting Your Project Under Source Control
- Working With JSON in Swift
Even though this list may seem daunting, a typical iOS project requires you to have these skills. If you have a basic understanding of iOS and Swift development, then this series teaches you how the various pieces fit together. You also learn some best practices that may become invaluable in your toolbox.
We start this series by creating and configuring the project in Xcode. We also take a close look at how we can improve the default structure of the project.
Project Setup
The first step is simple, setting up the project and updating the project structure. Open Xcode and create a new project by choosing the Single View Application template from the iOS > Application section.
Give the project a catchy name. I have named mine Thunderstorm. Set Language to Swift and devices to Universal. At the bottom, check Include Unit Tests to tell Xcode to create a unit test target. You can leave Use Core Data and Include UI Tests unchecked.
Click Next and tell Xcode where you'd like to save the files for the project. Leave the checkbox Create Git repository on My Mac unchecked. We put the project under source control later in this tutorial.
Project Structure
The project in Xcode shows us three groups:
- Products
- Thunderstorm
- ThunderstormTests
Before we put the project under source control, we need to add some structure to the project. This step is optional but it pays dividends in the long run by keeping your project and its files and folders organized.
Application Delegate
In the Project Navigator, right-click the Thunderstorm group, choose New Group, and name it Application Delegate. This creates a new group in the Thunderstorm group. Unfortunately, Xcode doesn't automatically create a folder for the group. We can easily fix this by selecting the new group, opening the File Inspector on the left and clicking the folder icon. This takes us to the location that corresponds to the group.
Click New Folder in the bottom right, name the folder Application Delegate, and click Choose. The Application Delegate group is now linked to the Application Delegate folder.
There is one problem. We need to add AppDelegate.swift to the Application Delegate folder. This is easy. Right-click AppDelegate.swift, choose Show in Finder, and drag AppDelegate.swift in the Application Delegate folder. The result is that AppDelegate.swift turns red. Why is that?
Xcode expects AppDelegate.swift to be in a certain location and we moved it to a different location. In general, it's not recommended to move files and folders of an Xcode project in Finder. At this stage of the project, though, we have no other option unless we create every file and folder from scratch.
To fix this, open the Project Navigator and drag AppDelegate.swift into the Application Delegate group. This still doesn't solve the problem because Xcode doesn't consider groups and folders to be the same thing.
To fix the issue, select AppDelegate.swift, open the File Inspector on the left, and click the folder icon we clicked earlier. In the Application Delegate folder, select AppDelegate.swift and click Choose. This tells Xcode where it can find AppDelegate.swift. Notice that AppDelegate.swift is no longer red in the Project Navigator.
Rinse & Repeat
We need to repeat these steps for the view controller, the assets, and the project's Info.plist. While this may seem cumbersome, I can assure you that it is much nicer to work with a project that is properly organized. This is especially true if the project gains in complexity over time.
I didn't mention the storyboards. If you right-click Main.storyboard and choose Show in Finder, you notice that it is located in a folder named Base.lproj. This indicates that the storyboard is localized. Personally, I never localize user interface files, including storyboards, because it makes managing translations a pain.
The solution is simple. In Finder, delete Base.lproj and, in Xcode, delete Main.storyboard and LaunchScreen.storyboard. Create a new group, Storyboards, and create a corresponding folder in Finder as I showed you earlier. Right-click the Storyboards group in the Project Navigator and choose New File.... Choose Storyboard from the iOS > User Interface section and name the storyboard Main.
Repeat these steps for the launch screen. Choose the Launch Screen template and name the storyboard LaunchScreen. This is what the project looks like when you are finished. It is important that you don't see any red file names.
And this is what the folder structure looks like in Finder.
We have one problem, though. Build and run the project in the simulator to find out what is wrong. The build fails because Xcode can no longer find the project's Info.plist. That's odd since the file doesn't show up in red in the Project Navigator.
Fortunately, this issue is easy to fix in Xcode. Select the project in the Project Navigator and choose the Thunderstorm target. At the top, the Identity section is empty because Xcode doesn't know where the target's Info.plist is located. It even shows us a button that says Choose Info.plist File.... Click the button and select the Info.plist we moved to the Supporting Files folder earlier.
Build and run the application again. Even though the application runs fine in the simulator, you see a black screen. This too is an easy fix. Open Main.storyboard and add a View Controller to the canvas from the Object Library on the left.
Select the View Controller object in the Document Outline, open the Identity Inspector on the right, and set Class to ViewController. With the view controller selected, open the Attributes Inspector and check Is Initial View Controller in the View Controller section to designate it as the initial view controller of the storyboard.
Build and run the application one more time. You should now see a white screen when the application has finished launching.
Source Control
With the project structure in great shape and the application building without issues, it's time to put the project under source control. Git is the most popular version control system for Cocoa development.
Before we set up Git, we need to add a .gitignore file at the root of the project. If you are unfamiliar with .gitignore files, then I recommend you read more about them first. This is the .gitignore file I currently use for Cocoa projects. Even though there are mentions of Xcode 4, it still works fine for me.
#########################
# .gitignore file for Xcode4 / OS X Source projects
#
# NB: if you are storing "built" products, this WILL NOT WORK,
# and you should use a different .gitignore (or none at all)
# This file is for SOURCE projects, where there are many extra
# files that we want to exclude
#
# For updates, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects
#########################
#####
# OS X temporary files that should never be committed
.DS_Store
*.swp
*.lock
profile
####
# Xcode temporary files that should never be committed
#
# NB: NIB/XIB files still exist even on Storyboard projects, so we want this...
*~.nib
####
# Xcode build files -
#
# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData"
DerivedData/
# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build"
build/
#####
# Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups)
#
# This is complicated:
#
# SOMETIMES you need to put this file in version control.
# Apple designed it poorly - if you use "custom executables", they are
# saved in this file.
# 99% of projects do NOT use those, so they do NOT want to version control this file.
# ..but if you're in the 1%, comment out the line "*.pbxuser"
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
# NB: also, whitelist the default ones, some projects need to use these
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
####
# Xcode 4 - semi-personal settings, often included in workspaces
#
# You can safely ignore the xcuserdata files - but do NOT ignore the files next to them
#
xcuserdata
####
# XCode 4 workspaces - more detailed
#
# Workspaces are important! They are a core feature of Xcode - don't exclude them :)
#
# Workspace layout is quite spammy. For reference:
#
# (root)/
# (project-name).xcodeproj/
# project.pbxproj
# project.xcworkspace/
# contents.xcworkspacedata
# xcuserdata/
# (your name)/xcuserdatad/
# xcuserdata/
# (your name)/xcuserdatad/
#
#
#
# Xcode 4 workspaces - SHARED
#
# This is UNDOCUMENTED (google: "developer.apple.com xcshareddata" - 0 results
# But if you're going to kill personal workspaces, at least keep the shared ones...
#
#
!xcshareddata
####
# XCode 4 build-schemes
#
# PRIVATE ones are stored inside xcuserdata
!xcschemes
####
# Xcode 4 - Deprecated classes
#
# Allegedly, if you manually "deprecate" your classes, they get moved here.
#
# We're using source-control, so this is a "feature" that we do not want!
*.moved-aside
# CocoaPods
/Pods
Launch the Terminal application and navigate to the root of the project. Initialize an empty Git repository by executing the git init
command.
git init
Add every file that isn't ignored to the staging area by executing the git add .
command.
git add .
We commit the changes we added to the staging area by executing git commit
. Note that I use the -m
flag to pass in the message of the commit.
git commit -m "Project setup"
This is what the output should look like.
[master (root-commit) 22de960] Project setup
11 files changed, 856 insertions(+)
create mode 100644 .gitignore
create mode 100644 Thunderstorm.xcodeproj/project.pbxproj
create mode 100644 Thunderstorm.xcodeproj/project.xcworkspace/contents.xcworkspacedata
create mode 100644 Thunderstorm/Application Delegate/AppDelegate.swift
create mode 100644 Thunderstorm/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json
create mode 100644 Thunderstorm/Storyboards/LaunchScreen.storyboard
create mode 100644 Thunderstorm/Storyboards/Main.storyboard
create mode 100644 Thunderstorm/Supporting Files/Info.plist
create mode 100644 Thunderstorm/View Controllers/ViewController.swift
create mode 100644 ThunderstormTests/Info.plist
create mode 100644 ThunderstormTests/ThunderstormTests.swift
Dark Sky
We're almost ready setting up the project. The application will fetch weather data from Dark Sky, a service that has been around for several years and is very easy to use. It has a simple API and you can create a free account if you want to follow along.
Swift makes parsing JSON quite challenging and I usually use a third party library to make this task less painful. Unbox is a great example of a library that abstracts away the nitty-gritty details. We won't be using any dependencies, though. It's a good exercise to learn what it takes to convert a JSON response into model objects that can be displayed by the application.
What's Next?
The project is set up and we are ready to start developing the application. In the next installment of this series, we build the basic user interface of the application. Remember that we are building a universal application that should look great on iPhone and iPad. You can find the source files of this tutorial on GitHub.