Using Swift extensions to manage complexity, improve readability, and increase extensibility (UICollectionView, protocols, and delegates)

[Download the full Xcode project from GitHub.]

Today, I’m going to show you how to leverage the Swift “extension” language feature to manage software complexity, improve code readability, and increase extensibility. We’ll also talk about delegates, data sources, and protocols as they are concepts essential to this tutorial. According to Apple’s “The Swift Programming Language (Swift 3.0.1):”


Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.)

Extensions in Swift can:

  • Make an existing type conform to a protocol …

Remember when I developed a UICollectionView sample app in my article entitled “UPDATE: The UICollectionView is much more than a grid or matrix?” I challenged you to answer the question “How could we break our UICollectionView code into smaller more manageable pieces — modularize our code — by taking advantage of Swift 3.0?” Before I explain everything, compare my original (and rather lengthy) subclass of a UIViewController to today’s code shown immediately below. Note that I’ve taken one subclass and split it into a smaller subclass and two small extensions. Notice that the extensions allowed me to divide and conquer my original code very logically and methodically. Download the whole Xcode 8.2.1 project, written in Swift 3.0, from GitHub and follow along. Here’s my project’s ViewController.swift file:

Figure 1. The Swift code for my project’s ViewController subclass of UIViewController.

Originally, all my code was stuffed into one class and was declared thusly:

Now, as shown above, I’ve made my code more maintainable, readable, and extensible. It’s easier to find code, and I’m less likely to break something when making edits, as functionality is grouped and compartmentalized:

Before discussing how I used Swift extensions, it’s important that you first understand how I subclassed a UIViewController in order to support a UICollectionView. Note that in my original code, the UIViewController subclass was declared as follows:

Protocol
My UIViewController is adopting the UICollectionViewDelegate and UICollectionViewDataSource protocols — and it has an IBOutlet to a UICollectionView in a storyboard. Apple says:

In the real world, people on official business are often required to follow strict procedures when dealing with certain situations. Law enforcement officials, for example, are required to “follow protocol” when making enquiries or collecting evidence.

In the world of object-oriented programming, it’s important to be able to define a set of behavior that is expected of an object in a given situation. …

Apple notes:

A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol. …


My UIViewController subclass has adopted the UICollectionViewDelegate and UICollectionViewDataSource protocols. I marked my class interface as conforming to two protocols. Then I made the ViewController class implement some required methods defined by those protocols so that the UICollectionView could work properly. Look at my code and notice where I’ve added inline commentary to clarify to the code reader where I’ve adopted those protocols:

I’ve conformed to the two protocols required to get a UICollectionView working. Without looking at the code, can you tell me what steps I must take next in order to make protocol conformance useful? Remember what my code does on an iPhone or iPad? Please watch:

Were you able to answer my last question? Without these steps, the UICollectionView won’t do anything. Let me explain. Notice two lines of code in my ViewController class’s viewDidLoad method:

I’ve told the Xcode compiler that my ViewController class (“self”) is 1) the delegate for the UICollectionView, and 2) the data source for the UICollectionView. According to Apple, the delegate is the “object that acts as the delegate of the collection view” and the data source is the “object that provides the data for the collection view.” Let’s get specific.

Delegate
The dictionary definition of “delegate” (Cambridge) is “to give a particular job, duty, right, etc. to someone else so that they do it for you.” The ViewController class has been given the duty of handling user events like a tap on a UICollectionViewCell — see didSelectItemAt for an example. The ViewController class has also been given the duty of configuring the UICollectionView’s behavior, like what happens when a user taps a cell, via delegated methods like shouldDeselectItemAt and shouldHighlightItemAt. According to Apple:

Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object–the delegate–and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object. …

and also:

A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program. The delegating object is often a responder object—that is, an object inheriting from NSResponder in AppKit or UIResponder in UIKit—that is responding to a user event. The delegate is an object that is delegated control of the user interface for that event, or is at least asked to interpret the event in an application-specific manner. …

The programming mechanism of delegation gives objects a chance to coordinate their appearance and state with changes occurring elsewhere in a program, changes usually brought about by user actions. More importantly, delegation makes it possible for one object to alter the behavior of another object without the need to inherit from it. The delegate is almost always one of your custom objects, and by definition it incorporates application-specific logic that the generic and delegating object cannot possibly know itself. …

Data Source
Unless your app is some type of abstract ideation of modern art, a UICollectionView needs a data source. You want your UICollectionViewCells to represent something. If you download one of my apps, you’ll see that I created a photo gallery’s entry point using a UICollectionView. It displays thumbnails in a grid of images. When you tap on a thumbnail (UICollectionViewCell), you segue to a larger version of the thumbnail. UICollectionViews are great for representing menu items, a list of books in a library, days of the month in the calendar, items in a shopping cart… In order for a UICollectionView to display a list of items, you need to tell it what object provides/vends/manages its data source.

In the project whose source code is displayed above in Figure 1 — and is the topic of this entire article — I use a simple array as the data source for my UICollectionView. The “collectionViewDataSource” array is a member of the class ViewController, and ViewController is set to be the “dataSource” property of my UICollectionView:

According to Apple:

Every collection view must have a data source object. The data source object is the content that your app displays. It could be an object from your app’s data model, or it could be the view controller that manages the collection view. The only requirement of the data source is that it must be able to provide information that the collection view needs, such as how many items there are and which views to use when displaying those items. …

The data source object is the object responsible for managing the content you are presenting using a collection view. The data source object must conform to the UICollectionViewDataSource protocol, which defines the basic behavior and methods that you must support. The job of the data source is to provide the collection view with answers to the following questions:

  • How many sections does the collection view contain?
  • For a given section, how many items does a section contain?
  • For a given section or item, what views should be used to display the corresponding content?

Sections and items are the fundamental organizing principle for collection view content. A collection view typically has at least one section and may contain more. Each section, in turn, contains zero or more items. Items represent the main content you want to present, whereas sections organize those items into logical groups. For example, a photo app might use sections to represent a single album of photos or a set of photos taken on the same day.

The collection view refers to the data it contains using NSIndexPath objects. …

I think you get the picture. In my extension for the UICollectionViewDataSource, I tell the UICollectionView how many sections — one — that UICollectionViewCells should be separated into via the numberOfSections delegate method, I keep the UICollectionView informed of how many cells to display via the numberOfItemsInSection method, and I tell the UICollectionView how and what to display in each cell via the cellForItemAt method. Do yourself a favor and read Apple’s “Collection View Basics” article, especially the section on “Designing Your Data Source and Delegate.”

Extension
After all this discussion, is it really necessary for me to go into a whole lot of detail into how to create a Swift extension? As a homework assignment, download my source code, read through it, run it in the simulator, run it on a device, set some breakpoints and walk through the code in the Xcode debugger. Please read Apple’s “The Swift Programming Language (Swift 3.0.1)” section entitled “Extensions.” Especially review the portion of the section called “Extension Syntax.” Check out the pseudo code:

An extension can extend an existing type to make it adopt one or more protocols. Where this is the case, the protocol names are written in exactly the same way as for a class or structure:

I hope you enjoyed this tutorial. Remember that the main purpose of this blog is to help new and aspiring iOS developers get started, and secondarily to help intermediate and advanced developers improve their skills. No matter which group you fall into, I want you to become the best of the best iOS developers. Come back soon for more.

[Download the full Xcode project from GitHub.]

Author: Andrew Jaffee

Avid and well-published author, software engineer, designer, and developer, now specializing in iOS mobile app development in Objective-C and Swift, but with a strong background in C#, C++, .NET, JavaScript, HTML, CSS, jQuery, SQL Server, MySQL, Oracle, Agile, Test Driven Development, Git, Continuous Integration, Responsive Web Design, blah, blah, blah ... Did I miss any fad-based catch phrases? My brain avatar was kindly provided by http://icons8.com under a Creative Commons Attribution-NoDerivs 3.0 Unported license.

Leave a Reply

Your email address will not be published. Required fields are marked *