Design Patterns on iOS using Swift – Part 1/2
In the first half of this two-part tutorial, you’ll learn about common design patterns when building iOS apps, and how to apply these patterns in your own apps. By Lorenzo Boaro.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Design Patterns on iOS using Swift – Part 1/2
30 mins
- Getting Started
- MVC – The King of Design Patterns
- How to Use the MVC Pattern
- The Singleton Pattern
- What Should You Be Careful About?
- How to Use the Singleton Pattern
- The Facade Design Pattern
- How to Use the Facade Pattern
- The Decorator Design Pattern
- Extensions
- How to Use Extensions
- Delegation
- How to Use the Delegate Pattern
- Final Touches
- Where to go from here?
How to Use the Delegate Pattern
Open up ViewController.swift and add these private properties to the class:
private var currentAlbumIndex = 0
private var currentAlbumData: [AlbumData]?
private var allAlbums = [Album]()
Starting from Swift 4, variables marked as private
can share the same access control scope between a type and any extension on said type. If you want to browse the new features introduced by Swift 4, take a look to What’s New in Swift 4?.
You’re going to make ViewController
the table view’s data source. Add this extension to the end of ViewController.swift, after the closing brace of the class definition:
extension ViewController: UITableViewDataSource {
}
The compiler will warn you because UITableViewDataSource
has a few mandatory functions. Add the following code inside the extension to make it happy:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let albumData = currentAlbumData else {
return 0
}
return albumData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if let albumData = currentAlbumData {
let row = indexPath.row
cell.textLabel!.text = albumData[row].title
cell.detailTextLabel!.text = albumData[row].value
}
return cell
}
tableView(_:numberOfRowsInSection:)
returns the number of rows to display in the table view, which matches the number of items in the “decorated” representation of the album.
tableView(_:cellForRowAtIndexPath:)
creates and returns a cell with the title and its value.
UITableViewDataSource
extension. For humans reading the code though, this kind of organization really helps with readability.
Next, replace viewDidLoad()
with this code:
override func viewDidLoad() {
super.viewDidLoad()
//1
allAlbums = LibraryAPI.shared.getAlbums()
//2
tableView.dataSource = self
}
Here’s a breakdown of the above code:
- Get a list of all the albums via the API. Remember, the plan is to use the facade of
LibraryAPI
rather thanPersistencyManager
directly! - This is where you setup the
UITableView
. You declare that the view controller is theUITableView
data source; therefore, all the information required byUITableView
will be provided by the view controller. Note that you can actually set the delegate and datasource in a storyboard, if your table view is created there.
Now, add the following method to the ViewController
class:
private func showDataForAlbum(at index: Int) {
// defensive code: make sure the requested index is lower than the amount of albums
if (index < allAlbums.count && index > -1) {
// fetch the album
let album = allAlbums[index]
// save the albums data to present it later in the tableview
currentAlbumData = album.tableRepresentation
} else {
currentAlbumData = nil
}
// we have the data we need, let's refresh our tableview
tableView.reloadData()
}
showDataForAlbum(at:)
fetches the required album data from the array of albums. When you want to present the new data, you just need to call reloadData
on the UITableView
. This causes the table view to ask its data source such things as how many sections should appear in the table view, how many rows in each section, and how each cell should look, etc.
Add the following line to the end of viewDidLoad()
showDataForAlbum(at: currentAlbumIndex)
This loads the current album at app launch. And since currentAlbumIndex
is set to 0
, this shows the first album in the collection.
Build and run your project. Your app should start and present you with the following screen:
Table view data source success!
Final Touches
In order to not pollute your code with hardcoded values, like the string Cell
, go to ViewController
and, just after the opening brace of the class definition, add the following:
private enum Constants {
static let CellIdentifier = "Cell"
}
Here you are creating an enumeration that acts as a container for your constants.
Now just replace "Cell"
with Constants.CellIdentifier
.
Where to go from here?
Things are looking pretty good so far! You have the MVC pattern in place, and you’ve also seen the singleton, facade, and decorator patterns in action. You can see how these are used within Cocoa by Apple, and also how to apply the patterns to your own code.
Here is the final project for this part if you want to have a look or compare.
There’s a lot more in store: there are still the adapter, observer, and memento patterns to cover in part two of this tutorial. And if that’s not enough, we have a follow-up tutorial coming up covering even more design patterns as you work on refactoring a simple iOS game.
If you have questions or just want to talk about your favorite design patterns, join in on the forum discussion below!