Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Swift Cookbook

You're reading from   Swift Cookbook Over 60 proven recipes for developing better iOS applications with Swift 5.3

Arrow left icon
Product type Paperback
Published in Feb 2021
Publisher Packt
ISBN-13 9781839211195
Length 500 pages
Edition 2nd Edition
Languages
Tools
Arrow right icon
Authors (3):
Arrow left icon
Chris Barker Chris Barker
Author Profile Icon Chris Barker
Chris Barker
Keith D. Moon Keith D. Moon
Author Profile Icon Keith D. Moon
Keith D. Moon
Keith Moon Keith Moon
Author Profile Icon Keith Moon
Keith Moon
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Swift Building Blocks 2. Mastering the Building Blocks FREE CHAPTER 3. Data Wrangling with Swift Control Flow 4. Generics, Operators, and Nested Types 5. Beyond the Standard Library 6. Building iOS Apps with Swift 7. Swift Playgrounds 8. Server-Side Swift 9. Performance and Responsiveness in Swift 10. SwiftUI and Combine Framework 11. Using CoreML and Vision in Swift 12. About Packt 13. Other Books You May Enjoy

Extending functionality with extensions

Extensions let us add functionality to our existing classes, structs, enums, and protocols. This can be especially useful when the original type is provided by an external framework, which means you aren't able to add functionality directly.

Getting ready

Imagine that we often need to obtain the first word from a given string. Rather than repeatedly writing the code to split the string into words and then retrieving the first word, we can extend the functionality of String to provide its own first word.

How to do it...

Let's get started:

  1. Create an extension of String:
extension String { 

}
  1. Within the extension's curly brackets, add a function that returns the first word from the string:
extension String {
func firstWord() -> String {
let spaceIndex = firstIndex(of: " ") ?? endIndex
let word = prefix(upTo: spaceIndex)
return String(word)
}
}
  1. Now, we can use this new method on String to get the first word from a phrase:
let llap = "Live long, and prosper" 
let firstWord = llap.firstWord()
print(firstWord) // Live

How it works...

We can define an extension using the extension keyword and then specify the type we want to extend. The implementation of this extension is defined within curly brackets:

extension String { 
//...
}

Methods and computed properties can be defined in extensions in the same way that they can be defined within classes, structs, and enums. Here, we will add a firstWord function to the String struct:

extension String {
func firstWord() -> String {
let spaceIndex = firstIndex(of: " ") ?? endIndex
let word = prefix(upTo: spaceIndex)
return String(word)
}
}

The implementation of the firstWord method is not important for this recipe, so we'll just touch on it briefly.

In Swift, String is a collection, so we can use the collection methods to find the first index of an empty space. However, this could be nil since the string may contain only one word or no characters at all, so if the index is nil, we must use the endIndex instead. The nil coalescing operator (??) is only used to assign endIndex if firstIndex(of: " ") is nil. More generally, it will evaluate the value on the left-hand side of the operator, unless it is nil, in which case it will assign the value on the right-hand side.

Then, we use the index of the first space to retrieve the substring up to the index, which has a SubString type. We then use that to create and return a String.

Extensions can implement anything that uses the existing functionality, but they can't store information in a new property. Therefore, computed properties can be added, but stored properties cannot. Let's change our firstWord method so that it's a computed property instead:

extension String {
var firstWord: String {
let spaceIndex = firstIndex(of: " ") ?? endIndex
let word = prefix(upTo: spaceIndex)
return String(word)
}
}

There's more...

Extensions can also be used to add protocol conformance, so let's create a protocol that we want to add conformance to:

  1. The protocol declares that something can be represented as an Int:
protocol IntRepresentable { 
var intValue: Int { get }
}
  1. We can extend Int and have it conform to IntRepresentable by returning itself:
extension Int: IntRepresentable { 
var intValue: Int {
return self
}
}
  1. Next, we'll extend String, and we'll use an Int constructor that takes a String and returns an Int if our String contains digits that represent an integer:
extension String: IntRepresentable { 
var intValue: Int {
return Int(self) ?? 0
}
}
  1. We can also extend our own custom types and add conformance to the same protocol, so let's create an enum that can be IntRepresentable:
enum CrewComplement: Int { 
case enterpriseD = 1014
case voyager = 150
case deepSpaceNine = 2000
}
  1. Since our enum is Int-based, we can conform to IntRepresentable by providing a rawValue:
extension CrewComplement: IntRepresentable { 
var intValue: Int {
return rawValue
}
}
  1. We now have String, Int, and CrewComplement all conforming to IntRepresentable, and since we didn't define String or Int, we have only been able to add conformance through the use of extensions. This common conformance allows us to treat them as the same type:
var intableThings = [IntRepresentable]() 
intableThings.append(55)
intableThings.append(1200)
intableThings.append("5")
intableThings.append("1009")
intableThings.append(CrewComplement.enterpriseD)
intableThings.append(CrewComplement.voyager)
intableThings.append(CrewComplement.deepSpaceNine)

let over1000 = intableThings.compactMap { $0.intValue > 1000 ?
$0.intValue: nil }
print(over1000)

The preceding example includes the use of compactMap and the ternary operator, which haven't been covered in this book. Further information can be found in the See also section.

See also

Further information about extensions can be found in Apple's documentation on the Swift language at http://swiftbook.link/docs/extensions.

The documentation for compactMap can be found at https://developer.apple.com/documentation/swift/sequence/2950916-compactmap.

Further information about the ternary operator can be found at https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html#ID71.

You have been reading a chapter from
Swift Cookbook - Second Edition
Published in: Feb 2021
Publisher: Packt
ISBN-13: 9781839211195
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime