Polymorphism in Swift 3: manipulate multiple related controls with one IBOutlet and one IBAction

How would you enable or disable multiple user interface controls using one IBOutlet and one IBAction? For example, you might need to disable a UITextBox and UISegmentedControl because a user’s login has expired. Perhaps a user hasn’t filled in some required fields on a form, so you want to disable several buttons. Watch the following video to see how I built a Swift 3 app to use a UISwitch to enable or disable four controls all at one time — and I demonstrated the object-oriented programming (OOP) principle of polymorphism:

Refresh your memory about OOP and inheritance.


The UITextField, UISlider, UISegmentedControl, and UIStepper classes are all descendants (children) of the UIControl parent class. The UITextField, UISlider, UISegmentedControl, and UIStepper classes all inherit some common properties and methods from UIControl, like isEnabled. Interestingly, in Apple’s documentation, isEnabled is only defined in UIControl and not in any of the four descendants I showed in my video, so I would think they inherit enabling/disabling functionality from their parent class.

You can set any of the UITextField, UISlider, UISegmentedControl, and UIStepper classes’ isEnabled properties to true or false. A value of true allows the user to interact with the control. A value of false prevents the user from interacting with the control.

Y’all should know what an outlet is by now. The following video demonstrates how I created an outlet collection (IBOutletCollection in Objective-C) and connected the UITextField, UISlider, UISegmentedControl, and UIStepper to that same outlet collection:

I typed in the Swift 3 outlet collection declaration (shown immediately below), built the project so that the little connector dot showed up next to the “@IBOutlet” keyword, then [control]-dragged from the dot to each of the four controls, and finally made sure that each one highlighted when I dragged the mouse on top of the control (which meant an outlet connections was made):

These steps resulted in an array of four different UIControls — and gave the array members a single name. This is really convenient if you have a large number of controls that you need to manipulate often, but note that you can still access each control separately. Look at Xcode’s Connections Inspector for each control and you’ll see its “Referencing Outlet Collections” (click to enlarge the image):

Figure 1. The Connections Inspector showing our outlet collection.

Remember we discussed options for finding, adding, and removing IBOutlets. [control]-click on another UIControl in our outlet collection (click to enlarge):

Figure 2. “Referencing outlet collections” for our 4 UIControls.

The point I’m trying to drive home is that we can leverage OOP polymorphism here. Remember that the origins (etymology) of the word “polymorphism” come “From Ancient Greek poly (many) + morph (form).”

With polymorphism, several descendant object/instance references can be assigned to a reference to the parent class, and yet the parent can exhibit the behavior of the descendant. In other words, you can declare a variable of a certain type (parent/UIControl) and it can store references of that type, but it can also store references to any child (subclass) of that type (here, UITextField, UISlider, UISegmentedControl, and UIStepper). This is where “poly (many) + morph (form)” comes into play.

#ad
   

Remember that multipleOutlets is declared as an array that can hold references to instances/objects of type UIControl. Yet I’ve connected outlets of type UITextField, UISlider, UISegmentedControl, and UIStepper — all child classes of UIControl — to multipleOutlets. The one multipleOutlets variable can take on many forms. I used an Xcode playground to illustrate what I’m talking about using Swift:

Here’s the output from the Swift “print” statements in the code block immediately above:

Download an Xcode 8.2.1 playground with full Swift 3 source code from GitHub and try this out yourself.

I wired up an IBAction (shown immediately below) that iterates over each UIControl descendant reference stored in multipleOutlets and sets their common isEnabled property to true or false (see highlighted lines 1, 11, 13, 18, 20):

Check out the output from the Swift “print” statement every time this IBAction is invoked. Note that a variable of type UIControl, multipleOutlets, can be assigned a variable of one of its descendant types — basically, it morphs into one of its child types:

Download the Xcode 8.2.1 project with full Swift 3 source code from GitHub and try this out yourself.

Polymorphism enables you to develop general code that works with groups of related classes instead of developing code for each individual class. I could’ve expanded this example and accessed any common methods and properties declared in UIControl that are inherited by its children (subclasses). Let’s talk about the possibilities.

I could’ve checked (and set in two cases) the isSelected, state, or isHighlighted properties of any UIControls in my outlet collection.

I could’ve programmatically associated a method with any of my outlet collection’s UIControl instances using addTarget(_:action:for:) with this syntax:

My development efforts could’ve gotten really granular by programmatically checking for user gestures on my UIControls with the class-family-common method beginTracking(_:with:) using the following syntax:

Pretty powerful stuff, eh? We’ll soon go through another example of a parent variable being assigned child instance references. As always, leave a comment if you have questions or feedback. Thanks!

#ad
   

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 https://icons8.com under a Creative Commons Attribution-NoDerivs 3.0 Unported license.