40,81 €
From learning about the most sought-after design patterns to a comprehensive coverage of architectural patterns and code testing, this book is all you need to write clean, reusable code
Key Features
Book Description
Swift keeps gaining traction not only amongst Apple developers but also as a server-side language. This book demonstrates how to apply design patterns and best practices in real-life situations, whether that's for new or already existing projects.
You'll begin with a quick refresher on Swift, the compiler, the standard library, and the foundation, followed by the Cocoa design patterns – the ones at the core of many cocoa libraries – to follow up with the creational, structural, and behavioral patterns as defined by the GoF. You'll get acquainted with application architecture, as well as the most popular architectural design patterns, such as MVC and MVVM, and learn to use them in the context of Swift. In addition, you'll walk through dependency injection and functional reactive programming. Special emphasis will be given to techniques to handle concurrency, including callbacks, futures and promises, and reactive programming. These techniques will help you adopt a test-driven approach to your workflow in order to use Swift Package Manager and integrate the framework into the original code base, along with Unit and UI testing.
By the end of the book, you'll be able to build applications that are scalable, faster, and easier to maintain.
What you will learn
Who this book is for
This book is for intermediate developers who want to apply design patterns with Swift to structure and scale their applications. You are expected to have basic knowledge of iOS and Swift.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 454
Veröffentlichungsjahr: 2018
Copyright © 2018 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the authors, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Kunal ChaudhariAcquisition Editor:Devanshi DoshiContent Development Editor:Francis CarneiroTechnical Editor:Sachin SunilkumarCopy Editor:Safis EditingProject Coordinator:Kinjal BariProofreader: Safis EditingIndexer:Mariammal ChettiyarGraphics:Alishon MendonsaProduction Coordinator:Priyanka Dhadke
First published: December 2018
Production reference: 1211218
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78913-556-5
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Florent Vilmart, M.Sc., is a full stack engineer in Montreal. Born in France, he moved to Montreal shortly before graduating, seeking exciting opportunities in the francophone metropole of North America. He honed his skills with Objective-C before jumping to Swift when it was released. He is a polyglot, and you can find his open source work on the parse community GitHub project, where he is one of the core maintainers. He has spoken at conferences, including the GitHub CodeConf in 2016 and, most recently, the 2017 Swift Summit in San Francisco. Currently, he is working full-time with BusBud in Montreal, using mainly TypeScript alongside Swift.
Giordano Scalzo is a developer with 20 years of programming experience, since the days of the ZX-Spectrum. He has worked in C++, Java, .NET, Ruby, Python, and in a multitude of other languages. After years of backend development, Giordano has developed extensively for iOS, releasing more than 20 apps which he wrote for clients, enterprise applications, or for his own benefit. Currently, he is a contractor in London where, through his company, Effective Code Ltd., he delivers code for iOS. For Packt, he has written two books on Swift, Swift by Example and Swift 2 by Example, and has reviewed a number of Swift books and videos, including Learn Swift by Building Applications, Introduction to Server-Side Swift, and Swift Functional Programming.
Sergio De Simone has been working as a software engineer for over twenty years across a range of different projects and companies, including work environments such as Siemens, HP, and small start-ups. For the last few years, his focus has been on developing mobile platforms and related technologies. He is currently working for BigML, Inc., where he leads iOS and OS X development. Additionally, he likes writing about technology, as well as programming tools, techniques, and languages, with a special focus on Swift evolution, for InfoQ.
Tibor Bödecs is an enthusiastic software developer with more than a decade of experience in the IT industry. Previously, Tibor was the technology leader at one of the biggest mobile development-focused companies in Hungary. He is a self-taught programmer with a true passion for Swift. He has the ability to work with different languages and technologies, and has extensive experience in product management. Nowadays, he is a freelance developer focusing predominantly on web, mobile, and server-side Swift projects. Tibor has a personal blog where he regularly writes about the Swift programming language.
Nikola Brežnjak is an engineer at heart and a jack of all trades. Currently, he's the director of mobile engineering at Teltech, where he is responsible for the management, mentoring, and coaching of mobile app developers. He loves his job! He has written books on the Ionic Framework and the MEAN stack, and has been a technical reviewer for a number of Packt books. He likes to help out on Stack Overflow, where he's a top contributor. He records a podcast called DevThink with his friend, Shawn Milochik, and runs a local meetup called MeCoDe.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Title Page
Copyright and Credits
Hands-On Design Patterns with Swift
About Packt
Why subscribe?
Packt.com
Contributors
About the authors
About the reviewers
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Download the color images
Conventions used
Get in touch
Reviews
Refreshing the Basics
Classes and structs
Classes
Struct
Enums
Simple enums
Adding methods
Associating values
Generic enums
Raw type enums
Switching the state of light
Closures, functions, and currying
Currying
Using closures as callbacks
Using weak and unowned
Protocols
Declaring a protocol
Conforming to a protocol
Conformance at declaration
Conformance in an extension
Protocol extensions
Default implementations
Tuples, type aliases, and generics
Tuples
Declaring tuples
Destructuring tuples
Using tuples in functions
Type aliases
Generics
Generic functions
Generic types
Generics, protocols, and associated types
Summary
Understanding ARC and Memory Management
A brief history of reference counting
The semantics of reference counting
Retain
Release
Assign
Copying
Using and misusing manual reference counting
Memory leaks
Dangling pointers
ARC – what is that?
Value types
Strong references
Weak references
Unowned references
Memory debugging
Configuring your project
Using the memory graph hierarchy tool
Leaks, cycles, and dangling references
Leaking with cycles
A simple leak
Fixing the leak
Using weak
Using unowned
Dangling references
Summary
Diving into Foundation and the Standard Library
Swift basic types
Working with ranges
Range as Sequence
Throwing and catching errors
Container types
Arrays
Mutability and operations
Iterating, mapping, and reducing
Dictionaries
Initialization and mutability
Iterating, mapping, and reducing
Mastering concurrency with Dispatch
Tasks and queues
Synchronization with Dispatch
Thread safety through serial queues
Organizing execution with groups and semaphores
Example of a counting semaphore
Using groups
HTTP with URLSession
Making your first call with URLSession
Parsing responses with Decodable
Sending requests with Encodable
Summary
Working with Objective-C in a Mixed Code Base
Setting up your project
Importing Objective-C in Swift
Exposing Swift to Objective-C
Nullability and optionals in Objective-C
Using NS_ASSUME_NON_NULL_BEGIN and NS_ASSSUME_NON_NULL_END
Using nullable, nonnull, _Nullable, and _Nonnull
Naming, renaming, and refining Objective-C for Swift
Setting Objective-C names from Swift
Setting Swift names from Objective-C
Renaming classes
Renaming methods and enum cases
Lightweight generics in Objective-C
Using typed NSArray* in Objective-C
Generic classes in Objective-C
Cocoa design patterns in Swift
Delegation
Using delegation
Implementing delegation 
Lazy initialization
Summary
Creational Patterns
The singleton pattern 
Using singletons
Singletons in a nutshell
The factory method pattern
Using the factory method pattern
Advanced usage of the factory method pattern
Wrapping up
The abstract factory pattern
Using the abstract factory pattern
Going further with factory methods
Default implementations
Inheritance
Protocol extensions
Checklist for using the factory method pattern
The builder pattern
Model building
Going further: metaprogramming with Sourcery
The builder pattern in a nutshell
The prototype pattern
Leveraging the prototype pattern
Going further – NSCopying with Sourcery
Implementing NSCopying automatically
Implementing mutable objects
Implementing NSMutableCopying automatically
The prototype pattern in a nutshell
Summary
Structural Patterns
The adapter pattern
Using the adapter pattern
The basics
The classes to adapt
Using classes as adapters
Leveraging extensions
The adapter pattern in a nutshell
The decorator pattern
Using a decorator 
Going further with decorator
Decoration in a nutshell
The facade pattern and proxy pattern
The facade pattern
Building a network cache with the facade pattern
Using the proxy pattern to implement request/response logging
The composite pattern
Using the composite pattern to represent tests and suites
The bridge pattern
Anatomy of the bridge pattern
Using the bridge pattern
The flyweight pattern
A shopping list using the flyweight pattern
Summary
Behavioral Patterns
The state pattern
The card reader
Using enums
Refactoring for maintainability
Extracting a single protocol
Implementing all states through structs, and moving the logic
Refactoring the context object
Using state machines
The observer pattern
Event-based programming
Using NotificationCenter
Using Key-Value Observing
Using KVO with existing Objective-C APIs
Using KVO with Swift
Observation using pure Swift
Using observation
The memento pattern
Components of the memento pattern
Implementing the memento pattern
Using the memento pattern
The visitor pattern
Visitable and visitor protocols
Contributors, thank you notes, and the visitor pattern
Using visitors
The strategy pattern
Components of the strategy pattern
The ice-cream shop example
Using the strategy pattern
Summary
Swift-Oriented Patterns
Getting started with protocol-oriented programming
A refresher on protocols
Adding requirements to protocols 
Mutation and value types
Protocols are full-fledged types
Generics, conditional conformance, and associated types
Generics-based programming
Generic functions
Generic everything
Conditional conformance
Associated types
A word on Self requirement
Protocol-oriented programming
The type erasure pattern
Elements of type erasure
Closure-based type erasure
Boxing-based type erasure
The abstract base class
The private box
The public wrapper
The type erasure pattern – a summary
Template pattern with protocol-oriented programming
A recommendation engine
Summing up with the template method pattern
Summary
Using the Model-View-Controller Pattern
A refresher on MVC
The theory behind the MVC pattern
A pure MVC example
The model layer
The view layer
The controller layer
UIViewController
View controller life cycles
UIViewController anti-patterns
Early view instantiation
Early view access in initializer
Early view access in properties
Composition and child view controllers
Adding child view controllers
Removing child view controllers
Using view controller composition
The model layer
Using model controllers
Refactoring controllers
View controllers
Model controllers
The Controller
Summary
Model-View-ViewModel in Swift
Basics of the MVVM pattern
Refactoring MVC into MVVM
Model
ViewModel
View
Benefits and drawbacks of MVVM
Enhanced testing
Improved reusability
Drawbacks
MVVM and data binding
Implementing the Observable class
Implementing the Binding protocol
Two-way binding on UITextField
Using Observables with ViewModels
Summary
Implementing Dependency Injection
Dependency Injection, a primer
What is Dependency Injection?
Definition
Why DI is useful
Separation of concerns
Testability
Dependency Injection by example
Four ways to use Dependency Injection (with examples)
Constructor Injection
Property Injection
Method Injection
Ambient Context
Bind the dependencies
Composition Root
DI anti-patterns
Control Freak
Stable and volatile dependencies
Bastard Injection
Service Locator
Using a Dependency Injection Container
Why you should use a DI Container
The Typhoon framework
Swinject
Automatic Storyboard Injection
Summary
Futures, Promises, and Reactive Programming
Callbacks and closures
Closures and memory management
The issue with callbacks
Futures and promises
Futures and promises under the hood
Futures and promises frameworks for Swift
PromiseKit
Google Promises
Reactive programming
RxSwift
Observables and observers
Transformations
Schedulers
Asynchronous networking – an example
Summary
Modularize Your Apps with Swift Package Manager
Creating a library package
Adding features to the library
Adding more targets
Adding third-party dependencies
Using SPM with Xcode
Extracting and sharing a framework
Refactoring your code
Extracting a framework
Summary
Testing Your Code with Unit and UI Tests
Unit testing using XCTest
Testing an RPN Calculator app
TDD
What is an reverse polish notation calculator?
A simple RPN Calculator app
The first test
More tests
Refactoring the tests
Adding operations
Learnings from our first TDD code
Assertions
Advanced testing with mocks, spy, and others
Testing in Isolation
Dummy test double: when we don't need to test the collaborator
Fake test double: a simplified collaborator
Stub test double: a predefined collaborator
Spy test double: verifying collaboration
Mock test double: asserting collaboration
UI testing with Xcode
The importance of UI testing
Recording a UI test
Writing UI tests in code
Tips and tricks
Testing singletons
Testing Async code
Run only the test with the cursor
Summary
Going Out in the Open (Source)
Documenting Swift
The Markdown language
The anatomy of a documentation block
Rich content
Additional callouts
Structural annotations
Generating HTML docs
Publishing to GitHub Pages
Continuous integration
Travis CI
Configuring simple projects
Configuring more complex build scenarios
Configuring pure Swift projects
GitLab.com
Building and testing
Adding a linter, SwiftLint
Some final words on Travis and GitLab
Using fastlane for automated delivery
Getting started with fastlane
Your first lane
Fastlane beta
Using Travis to upload on tags
Becoming a maintainer, tips and tricks
The README.md file
The LICENSE.md file
The CODE_OF_CONDUCT.md file
Issues, Pull Requests, and more
No is temporary, yes is forever
Summary
Other Books You May Enjoy
Leave a review - let other readers know what you think
Hands-on Design Patterns in Swift provides a complete overview of how to implement classic design patterns in Swift. Swift is a modern language, and for users coming from a purely object-oriented language background, it may feel overwhelming. It has peculiar characteristics that create new programming paradigms, such as protocol programming, and appropriate solutions to problems such as type erasure. Both of these are covered in this book.
Design patterns do not live in isolation, however, but they help to solve real-world problems. Particular attention is given to presenting them in a number of realistic scenarios.
The goal of Swift is to create robust and maintainable apps, be they mobile or server. However, well-known techniques such as dependency injection and automatic testing are taken from other programming languages.
Finally, since most of the modern software relies upon open source, the final chapter shows how to release and maintain a Swift open source package.
This book is designed for intermediate and advanced developers who already have experience of another programming language and some experience of Swift.
Those readers with no previous experience in Swift may find an examination of the basics in the first part of the book beneficial.
The second part demonstrates how to implement the classic creational, behavioral, and structural design patterns, as well as those peculiar to Swift patterns. In this section, experienced developers will find both similarities and differences with their favorite programming language.
This isn't an academic book, but it aspires to show readers how to implement an app in a pragmatic and practical way. Consequently, the third part is devoted to how to implement an application architecture, presenting patterns such as MVC and MVVM, as well as how to create a couple of modules loosely with dependency injection, and how to handle asynchronous code with futures, promises and reactive programming.
The final part shows how to make apps robust and maintainable. After providing advanced readers with an overview of the Swift testing ecosystem, particular attention is given to the open source maintainers between the readers, showing how to release and maintain a Swift open source package or app.
Chapter 1, Refreshing the Basics, introduces the building blocks that facilitate the writing of Swift code: classes, structs, enums, functions, and closures. Those basics are essential to the Swift language and for successfully applying efficient design patterns and best practices.
Chapter 2, Understanding ARC and Memory Management, describes the particular memory management strategy Swift uses. From its origins in Objective-C, during the pre-ARC era, to today, we'll discover how to properly manage our memory and object life cycles.
Chapter 3, Diving into Foundation and the Swift Standard Library, discusses the powerful framework that comes with Swift. Alongside basic data structures such as arrays and dictionaries, it also comes with a fully featured concurrency management abstraction library (GCD), a full modern networking API (URLSession), and many more features besides.
Chapter 4, Working with Objective-C in a Mixed Code Base, covers the basics of interoperability, nullability, naming conventions, and lightweight generics, as well as the common pitfalls to avoid when bringing Objective-C code to Swift.
Chapter 5, Creational Patterns, dives into the traditional creational design patterns. Examples of Singleton, Abstract Factories, Prototype, Factory, and Builder are shown by means of detailed use cases.
Chapter 6, Structural Patterns, explores the most popular structural patterns, starting with the adapter pattern. We'll follow that up with implementing decorators, facades, and proxies, and finish with exploring composite, bridge, and flyweight patterns.
Chapter 7, Behavioral Patterns, shows patterns that identify common communication strategies between different entities. We'll see examples of the state pattern, observer/observable, memento, visitor, and the strategy pattern.
Chapter 8, Swift-Oriented Patterns, presents patterns peculiar to Swift. After introducing protocol programming, it shows how to implement the classic template pattern using protocol programming. Finally, it shows the type erasure pattern, a powerful tool for mastering generics.
Chapter 9, Using the Model-View-Controller Pattern, explores some best practices and decoupling strategies to keep the view controllers as lean as they should be. The classic Model View Controller pattern is discussed, as are other popular controllers available in UIKit and AppKit.
Chapter 10, Model-View-ViewModel in Swift, explores an extension of MVC, the Model-View-ViewModel pattern. MVVM is a very popular and flexible pattern that avoids the "bloated view controller" effect.
Chapter 11, Implementing Dependency Injection, covers the different flavors of dependency injection and examines how each can solve a particular set of problems in real-world scenarios.
Chapter 12, Futures, Promises, and Reactive Programming, discusses how to solve the most common asynchronous code problems. It explores futures and promises as an encapsulation of work being done. Finally, it provides an overview of signals and reactive programming.
Chapter 13, Modularize Your Apps with Swift Package Manager, shows how Swift Package Manager can power your workflow and keep your project in check, all while increasing the modularity and maintainability of your code base.
Chapter 14, Testing Your Code with Unit and UI Tests, shows how to write unit tests, what they are, what you should look for, and how to get started with testability. The chapter on dependency injection concludes with a presentation of the different types of test doubles to test in isolation, along with an introduction to UI testing.
Chapter 15, Going Out in the Open (Source), discusses the steps required before you can put your project in the open, documenting the source code with Jazzy, using continuous integration with Travis, and automating release with Fastlane.
This book uses Xcode version 10 and Swift 4.2. If you use a different version of Xcode, you will likely encounter syntax difference. To upgrade the Swift syntax and update the code examples of this book to a newer version of Xcode, you can use Xcode's Edit | Convert | To Current Swift Syntax option.
Visit https://developer.apple.com/xcode/ to download Xcode.
You can download the example code files for this book from your account at www.packt.com. If you purchased this book elsewhere, you can visit www.packt.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packt.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Hands-On-Design-Patterns-with-Swift. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
We also provide a PDF file that has color images of the screenshots/diagrams used in this book. You can download it here: https://www.packtpub.com/sites/default/files/downloads/9781789135565_ColorImages.pdf.
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "Mount the downloaded WebStorm-10*.dmg disk image file as another disk in your system."
A block of code is set as follows:
func translate(point : Point, dx : Double, dy : Double) { point.x += dx point.y += dy}
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
func translate(point : Point, dx : Double, dy : Double) {
point.x += dx
point.y += dy
}
Any command-line input or output is written as follows:
$ gem install jazzy
$ jazzy
Bold: Indicates a new term, an important word, or words that you see on screen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "Navigate to the Diagnostics tab."
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packt.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in, and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packt.com.
In order to properly kick-start our journey through Swift's best practices and design patterns, I believe it's important that we take some time to go back to the basics. It's important to always keep your foundation strong; the more we advance through this book, the more we'll rely on those concepts.
I'll assume that you have a proper understanding of object-oriented programming (OPP) fundamentals, classes, inheritance, composition, and other techniques, as well as a fundamental understanding of the differences between value and reference types. If you're rusty on these concepts, you shouldn't worry too much, as we'll cover them shortly.
This chapter will dive deeply into the Swift language. What is a struct, and what is a class? What are their differences? Should you use an enum or an OptionSet? All of these questions will be answered in this chapter. We'll go back to the basics of classes and inheritance, and we'll discover the power of value types and immutability. We'll look it functions, closures, and currying. If you're unfamiliar with these constructs, or if you just want to get a refresher, you should tag along as we go back to the basics. These basics are essential to the Swift language, and are required to successfully apply efficient design patterns and best practices.
In this first chapter, we'll take the time to go back to the basics by covering the following topics:
Classes and structs: what they are, and how they behave
Exploring enums and their capabilities and extensibility
Getting functional with closures and functions
Introducing protocols and scratching the surface of extending protocols
Concluding with other useful language constructs, such as type aliases, tuples, and generics
Let's start with a quick refresher on classes and structures. Both of them help to encapsulate functionality by defining methods and properties. While they share the same semantics, they differ in many ways. In this section, we'll quickly refresh you on the differences between classes and structs, and we will show you a simple refactoring from classes to structs.
Enums are one of the basic constructs that the Swift language offers. At the same level as classes, structs, and functions, they are used to represent values that can only have a finite amount of states.
Take the Optional enum, for example; it is represented by an enum perfectly. It represents a value that can have two, and only two, states, represented by the two members of the Optional enum. It can either be initialized to .none or filled with a value, .wrapped(value).
Enums are incredibly powerful in Swift. From very simple cases to generics, they are among the most powerful tools that we have for writing our programs.
Enums can also contain associated values. In our scenario, we can leverage this to represent a dimmer. A dimmer changes the intensity of the light, so we can represent it with a third member-the dimmed member:
enum State: Equatable { case on case off case dimmed(value: Double)}
You may have noticed that we needed to add the Equatable conformance. This is required, as otherwise, the compiler can't synthesize equality anymore without our hint. This implementation works, but we lack a few things. First, not all Double values are valid; we'd probably like to keep these in a reasonable span (between 0 and 1, for example). But perhaps not all of our lights support such values between 0 and 1. Others may want to support between 0 and a 100 or integers between 0 and 255.
With our final case, let's look at how to interpret the current state of the light:
switch state {case .on: doSomething()case .off: doSomething()case .dimmed(let value): switch value { case .quarter: doSomething() case .half: doSomething() case .threeQuarters: doSomething() }}
The switch statement in Swift is very different from the one in Objective-C. First, the cases do not fall through each other, so there's no need to add the break statement after each case.
If you want multiple cases to be handled with the same code, you can use the following strategy:
switch state {case .on, .off: doSomething()default: break}
Falling through is somehow not encouraged in Swift, so always try to adapt your code in order not to leverage this. If you can't avoid it, the following code shows how it should be implemented:
switch state {case .off: doSomethingOff() fallthroughcase .on: doSomething()default: break}
If state is off, both doSomethingOff and doSomething will be called. If state is on, only doSomething will be called.
The following is from Apple's Swift Programming Language book:
Protocol-oriented programming is a vast topic that also deserves coverage. It is the subject of many discussions, and I won't dive into it in depth. However, let's go over the basic concepts, as they will be useful for understanding some concepts that will be explained later in this book.
You declare protocols using the protocol keyword, as follows:
protocol Toggling { mutating func toggle()}
Now that this protocol has been declared, any time that you declare a type conforming to Toggling, you'll be required to implement a mutating toggle() function.
You can use protocols in your type declarations, method declarations, or variable declarations. While it is technically possible to use protocols as interfaces for your objects or structs, that is usually not how they are used in Swift. Often, you will find yourself conforming to protocols when declaring your custom types or later in your code base, part of extending your existing type to bring additional functionality to it.
We have just declared this new toggling protocol. If we go back to the previous section about enums, you may remember that the State enum had a toggle() method. We can now declare that our enum, State, conforms to Toggling. As mentioned previously, we have many ways to declare our conformance.
It is possible to provide default implementations for protocols through extensions. Previously, we provided a partial default implementation for the Toggling protocol on a well-known type. But any other type, that would conform to Toggling needs to provide an implementation on isActive. Using another example, let's look at how we can leverage default implementations in protocol extensions without requiring additional conformance work.
Let's work with a simple protocol, Adder, for the sake of the example:
protocol
Adder {
func
add(value:
Int
) ->
Int
func
remove(value:
Int
) ->
Int
}
The Adder protocol declares two methods: add and remove. And, if we remember our math classes well, we can very well declare remove as a function of add. Removing is just adding a negative value. Protocol extension allows us to do just that:
extension
Adder
{
func
remove(value:
Int
) ->
Int
{
return
add
(value: -value) }}
This may look a bit silly, but in reality, this pattern is really powerful. Remember, we were able to implement remove because we were able to express it as a function of another provided method. Often, in our code, we can implement a method as a function of another. Protocols give us a contract that is fulfilled by either the concrete type or the extension, and we can effectively and expressively compose our programs around those capabilities.
This chapter would not be complete if we didn't address some very useful features from Swift. Tuples are very useful types that let you return multiple objects as one, without a strongly typed wrapper. Aliases let you quickly define simple type shortcuts. Finally, we'll cover the basics of generics. While generics could be covered in a whole book, we'll just scratch the surface of their syntax, features, and limits, as we'll make use of them extensively throughout this book.
Tuples are used to represent a group of values as a single value. Tuples cannot conform to protocols, nor can they inherit. They cannot declare functions in the same way that we can declare a function on a struct or a class. They may look limited, but they have their place as first-class types in the language.
Generics is a complex subject, and would likely require a full book of its own, for extensive coverage extensively. For the purpose of this book, we'll provide a quick refresher on generics, covering the basics that are required to understand the constructions that we'll use in the different design patterns presented in the next chapters.
In Swift, the simplest form of generics would be the generics in functions. You can use generics very simply, with angled brackets, as follows:
func concat<T>(a: T, b: T) -> [T] { return [a,b]}
The concat method knows nothing about the types that you are passing in, but generics gives us many guarantees over using Any:
a
and
b
should be of the same type
The
return
type is an array of elements that have the same type as
a
and
b
The type is inferred from the context so you don't have to type it in when you code
