In this chapter, we will cover the following topics:
Using closures to create self-contained code
Creating enumerations to write readable code
Working with protocols and delegates
Using extensions to extend classes functionality
Working with memory management and ARC
Using error handling
Using generics to write generic and reusable code
Welcome to our first chapter in iOS Programming Cookbook. We will start our journey in this book with a revision or emphasize on the most important and commonly used topics in Swift programming language. Before talking about these topics, ensure that you have a basic knowledge about Swift programming language and have used it before.
It has been more than 2 years since Apple released the awesome programming language-Swift. Swift is meant to be easy to code, easy to learn, safe, and intuitive. For each version of Swift, Apple introduces some awesome features and enhancements in the language. As we see in Swift 2.0, Swift came with higher performance, and new APIs such as error handling, and some enhancements. Swift is not meant to be available in iOS development only; you may find it in other platforms later in the future, thanks to the announcement of Apple that Swift will become open source.
Our recipes in this chapter will focus on the most important topics in Swift that will be used frequently in iOS development. When you focus on these topics and learn them properly, you will find using them in development will make your life easier and your code will be more organized. There are many people who can write code, but only few can write awesome code. Thus, mastering these topics is very important to be a good developer and to help you and others working on a project.
Closures are self-contained lines of code to be executed and passed like any other data types. You should be familiar with blocks or at least heard about them in Objective-C or C. This recipe will help you to understand closure syntax and get familiar in using them.
Closures syntax in Swift is pretty easy and is easier than the syntax in C or Objective-C. The general form of closure is as follows:
{ (parameters) ->returnType in // block of code goes here }
As you see, you first put open curly braces, add list of parameters and the return type, then the keyword in
, followed by lines of code in your closure. Closures are first-class type, which means it can be nested, passed in parameters, returned from function, and so on.
Go to Xcode and create a new playground file called
Closures
to test code about closures in it.To see closures in action, copy and paste this piece of code in the playground file (the output of each statement is printed on the right):
var names = ["David", "Jones", "Suzan", "Naomi", "Adam"] names.sort() // ["Adam", "David", "Jones", "Naomi", "Suzan"] names.sort{ (str1: String, str2: String) ->Bool in return str1 > str2 } // ["Suzan", "Naomi", "Jones", "David", "Adam"]
Swift provides us with a built-in system function called sort
. The function can sort any collection of data. The function, by default, will sort the collection in an ascending order. The sort
function gives us another flexibility by which you can provide a closure that returns the comparison result between any two items in the list to determine which should come first in the list.
As we saw, the default sort
function sorts our data in an ascending order; in order to do any other logic, we can sort with closure that gives you two items as parameters to decide how to compare them. The sort
function sorts the collection in place, and that's why the names variable is created as var
not let
. If the names collection is defined as let
, you will not be able to use the sort()
function. There is another function called sorted()
, which returns a totally new sorted collection without changing the original one. It's available in both versions of the collection with var
or let
.
Even though the closure syntax looks simple, but Swift can make it simpler. Let's see how closure syntax can be optimized.
When closures are passed as argument like what we did in the sort
function, Swift can infer the types of closure parameters and return type. In that case, we can omit the parameters and return types, as there is no need to write them. In our previous example, when we infer types, the sort
function would be like this:
names.sort{ str1, str2 in return str1 > str2 }
As you can see, the String
types and the return type have been omitted.
Swift can make your life easier than that. When closure body consists of only one expression, the return
keyword can be omitted. So, the new version of sort
function will be like this:
names.sort({ str1, str2 in str1 > str2})
To reach the maximum awesomeness of Swift, you can refer to the argument list with names $0
, $1
, and so on. When you decide to use the shorthand arguments, you can omit the list of parameters. You may ask what about the in
keyword, will it be alone? The answer is no, we won't leave it alone; we can omit it as well completely. Here is the final version of our sort
function:
names.sort({ $0 > $1})
Using enumerations is one of the best practices that you should follow while writing any software project and not only iOS projects. Once you find that you have a group of related values in your project, create enum
to group these values and to define a safe type for these values. With enumerations, your code becomes more readable and easy to understand, as it makes you define new types in your project that map to other value. In Swift, enumerations have been taken care of and have become more flexible than the ones used in other programming languages.
Now, we will dive into enumerations and get our hands dirty with it. To do so, we will create a new playground file in Xcode called Enumerations
so that we can practice how to use enumerations and also see how it works.
Writing enumerations is meant to be easy, readable, and straightforward in syntax writing in Swift. Let's see how enum
syntax goes:
enum EnumName{ }
You see how it's easy to create enums; your enumeration definition goes inside the curly braces.
Now, let's imagine that we are working on a game, and you have different types of monsters, and based on the type of monster, you will define power or the difficulty of the game. In that case, you have to use enum to create a monster type with different cases, as follows:
Type the following code to create enum with name
Monster
:enum Monster{ case Lion case Tiger case Bear case Crocs } enum Monster2{ case Lion, Tiger, Bear, Crocs }
Use the '
.
' operator to create enums variables from the previously created enum:var monster1 = Monster.Lion let monster2 = Monster.Tiger monster1 = .Bear
Use the
switch
statement to check the value of enum to perform a specific action:func monsterPowerFromType(monster:Monster) ->Int { var power = 0 switch monster1 { case .Lion: power = 100 case .Tiger: power = 80 case .Bear: power = 90 case .Crocs: power = 70 } return power } let power = monsterPowerFromType(monster1) // 90 func canMonsterSwim(monster:Monster) ->Bool{ switch monster { case .Crocs: return true default: return false } } let canSwim = canMonsterSwim(monster1) // false
Now, you have a new type in your program called Monster
, which takes one value of given four values. The values are defined with the case
keyword followed by the value name. You have two options to list your cases; you can list each one of them in a separate line preceded by the case
keyword, or you can list them in one line with a comma separation. I prefer using the first method, that is, listing them in separate lines, as we will see later that we can add raw values for cases that will be more clear while using this method.
Note
If you come from a C or Objective-C background, you know that the enums values are mapped to integer values. In Swift, it's totally different, and they aren't explicitly equal to integer values.
The first variable monster1
is created using the enum name followed by '.
' and then the type that you want. Once monster1
is initialized, its type is inferred with Monster
; so, later you can see that when we changed its value to Bear
, we have just used the '.
' operator as the compiler already knows the type of monster1
.
However, this is not the only way that you will use enums. Since enums is a group of related values, so certainly you will use it with control flow to perform specific logic based on its value. The switch
statement is your best friend in that case as we saw in the monsterPowerFromType()
function.
We've created a function that returns the monster power based on its type. The switch
statement checks all values of monster with '.
' followed by an enum value. As you already know, the switch
statement is exhaustive in Swift and should cover all possible values; of course, you can use default in case it's not possible to cover all, as we saw in the canMonsterSwim()
function. The default
statement captures all non-addressed cases.
Enumerations in Swift have more features, such as using enums with raw values and associated values.
We saw how enums are defined and used. Enum cases can come with predefined values, which we call raw values. To create enums with raw values, the following rules should be adhered:
All raw values should be in the same type.
Inside the enum declaration, each raw value should be unique.
Only possible values allowed to use are strings, characters, integer, and floating point numbers.
When you assign raw values to enum
, you have to define the type in your enum syntax and give value for each case
:
enum IntEnum: Int{ case case1 = 50 case case2 = 60 case case3 = 100 }

Swift gives you flexibility while dealing with raw values. You don't have to explicitly assign a raw value for each case in enums if the type of enum is Int
or String
. For Int
type enums, the default value of enum is equal to the value of previous one + 1. In case of the first case, by default it's equal to 0
. Let's take a look at this example:
enum Gender: Int{ case Male case Female case Other } var maleValue = Gender.Male.rawValue // 0 var femaleValue = Gender.Female.rawValue // 1
We didn't set any raw value for any case, so the compiler automatically will set the first one to 0
, as it's a no set. For any following case, it's value will be equal to previous case value + 1. Another note is that .rawValue
returns the explicit value of the enum case. Let's take a look at another complex example that will make it crystal clear:
enum HTTPCode: Int{ case OK = 200 case Created // 201 case Accepted // 202 case BadRequest = 400 case UnAuthorized case PaymentRequired case Forbidden } let pageNotFound = HTTPCode.NotFound let errorCode = pageNotFound.rawValue // 404
We have explicitly set the value of first case to 200
; so, the following two cases will be set to 201
and 202
, as we didn't set raw values for them. The same will happen for BadRequest
case and the following cases. For example, the NotFound
case is equal to 404
after incrementing cases.
Now, we see how Swift compiler deals with Int
type when you don't give explicit raw values for some cases. In case of String
, it's pretty easier. The default value of String
enum cases will be the case name itself. Let's take a look at an example:
enum Season: String{ case Winter case Spring case Summer case Autumn } let winter = Season.Winter let statement = "My preferred season is " + winter.rawValue // "My preferred season is Winter"
You can see that we could use the string value of rawValue
of seasons to append it to another string.
We saw how easy it is to create enums with raw values. Now, let's take a look at how to get the raw value of enums or create enums back using raw values.
We already saw how to get the raw value from enum by just calling .rawValue
to return the raw value of the enum case.
To initialize an enum with a raw value, the enum should be declared with a type; so in that case, the enum will have a default initializer to initialize it with a raw value. An example of an initializer will be like this:
let httpCode = HTTPCode(rawValue: 404) // NotFound let httpCode2 = HTTPCode(rawValue: 1000) // nil
The rawValue
initializer always returns an optional
value because there will not be any matching enum for all possible values given in rawValue
. For example, in case of 404
, we already have an enum whose value is 404
. However, for 1000
, there is no enum with such value, and the initializer will return nil
in that case. So, before using any enum initialized by the rawValue
initializer, you have to check first whether the value is not equal to nil
; the best way to check for enums after initialization is by this method:
if let httpCode = HTTPCode(rawValue: 404){ print(httpCode) } if let httpCode2 = HTTPCode(rawValue: 1000){ print(httpCode2) }
The condition will be true only if the initializer succeeds to find an enum with the given rawValue
.
Last but not least, we will talk about another feature in Swift enums, which is creating enums with associated values. Associated values let you store extra information with enum case value. Let's take a look at the problem and how we can solve it using associated values in enums.
Suppose we are working with an app that works with products, and each product has a code. Some products codes are represented by QR code format, but others by UPC format. Check out the following image to see the differences between two codes at http://www.mokemonster.com/websites/erica/wp-content/uploads/2014/05/upc_qr.png):

The UPC code can be represented by four integers; however, QR code can be represented by a string value. To create an enum to represent these two cases, we would do something like this:
enum ProductCode{ case UPC(Int, Int, Int, Int) case QR(String) } var productCode = ProductCode.UPC(4, 88581, 1497, 3) productCode = ProductCode.QR("BlaBlaBla")
First, UPC is a case, which has four integer values, and the second is a QR, which has a string value. Then, you can create enums the same way we created before in other enums, but here you just have to pass parameters for the enum. When you need to check the value of enum with its associated value, we will use a switch
statement as usual, but with some tweaks:
switch productCode{ case .UPC(let numberSystem, let manufacturerCode, let productCode, let checkDigit): print("Product UPC code is \(numberSystem) \(manufacturerCode) \(productCode) \(checkDigit)") case .QR(let QRCode): print("Product QR code is \(QRCode)") } // "Product QR code is BlaBlaBla"
Protocol is a set of methods and properties for a particular task to which classes, structure, or enumeration can be conformed.
The syntax of protocol goes like this:
protocol ProtocolName{ // List of properties and methods goes here.... }
The keyword protocol
followed by the protocol name and curly braces are the building blocks of any protocol you need to write. Classes, structures, or enumeration can then conform to it like this:
class SampleClass: ProtocolName{ }
After class name, you type colon
and the super class name that this class extend from if any, followed by a list of protocols that you want to conform to with a comma separation.
Create a new playground file in Xcode called
Protocols
as usual.Complete the following example using the following protocol:
protocol VehicleProtocol{ // properties var name: String {set get} // settable and gettable var canFly: Bool {get} // gettable only (readonly) // instance methods func numberOfWheels() ->Int func move() func stop() // class method staticfuncpopularBrands() -> [String] } class Bicycle: VehicleProtocol{ var name: String var canFly: Bool{ return false } init(name: String){ self.name = name } func numberOfWheels() -> Int { return 2 } func move() { // move logic goes here } func stop() { // stop logic goes here } static func popularBrands() -> [String] { return ["Giant", "GT", "Marin", "Trek", "Merida", "Specialized"] } } class Car: VehicleProtocol{ var name: String var canFly: Bool{ return false } init(name: String){ self.name = name } funcnumberOfWheels() ->Int { return 4 } func move() { // move logic goes here } func stop() { // stop logic goes here } static func popularBrands() -> [String] { return ["Audi", "BMW", "Honda", "Dodge", "Lamborghini", "Lexus"] } } let bicycle1 = Bicycle(name: "Merida 204") bicycle1.numberOfWheels() // 2 let car1 = Car(name: "Honda Civic") car1.canFly // false Bicycle.popularBrands() // Class function // ["Giant", "GT", "Marin", "Trek", "Merida", "Specialized"] Car.popularBrands() // ["Audi", "BMW", "Honda", "Dodge", "Lamborghini", "Lexus"]
We started by defining VehicleProtocol
that has a list of properties and functions that every vehicle should have. In properties, we have two types of properties: name
, which is marked as {get set}
, and canFly
, which is marked as {get}
. When you mark a property {get set}
, it means it's gettable and settable, whereas {get}
means it only gettable, in other words, it's a read-only property. Then, we added four methods, out of which three methods-numberOfWheels()
, move()
, and stop()
-are instance methods. The last one-popularBrands()
- marked as static
is a type method. Types methods can be called directly with type name, and there is no need to have instance to call it.
Then, we created two new classes, Bicycle
and Car
, which conform to VehicleProtocol
, and each one will have different implementations.
We have already covered the most important parts of protocols and how to use it, but still they have more features, and there are many things that can be done with it. We will try here to mention them one by one to see when and how we can use them.
Swift allows you mark protocol methods as mutating when it's necessary for these methods to mutate (modify) the instance value itself. This is applicable only in structures and enumerations; we call them value types. Consider this example of using mutating:
protocol Togglable{ mutating func toggle() } enum Switch: Togglable{ case ON case OFF mutating func toggle() { switch self { case .ON: self = OFF default: self = ON } } }
The Switch
enum implements the method toggle
, as it's defined in the protocol Togglable
. Inside toggle()
, we could update self-value as function marked as mutating
.
Delegation is the most commonly used design pattern in iOS. In delegation, you enable types to delegate some of its responsibilities or functions to another instance of another type. To create this design pattern, we use protocols that will contain the list of responsibilities or functions to be delegated. We usually use delegation when you want to respond to actions or retrieve or get information from other sources without needing to know the type of that sources, except that they conform to that protocol. Let's take a look at an example of how to create use delegate:
@objc protocol DownloadManagerDelegate { func didDownloadFile(fileURL: String, fileData: NSData) func didFailToDownloadFile(fileURL: String, error: NSError) } class DownloadManager{ weak var delegate: DownloadManagerDelegate! func downloadFileAtURL(url: String){ // send request to download file // check response and success or failure if let delegate = self.delegate { delegate.didDownloadFile(url, fileData: NSData()) } } } class ViewController: UIViewController, DownloadManagerDelegate{ func startDownload(){ letdownloadManager = DownloadManager() downloadManager.delegate = self } func didDownloadFile(fileURL: String, fileData: NSData) { // present file here } func didFailToDownloadFile(fileURL: String, error: NSError) { // Show error message } }
The protocol DownloadManagerDelegate
contains methods that would be called once the specific actions happen to inform the class that conforms to that protocol. The DownloadManager
class performs the download tasks asynchronously and informs the delegate with success or failure after it's completed. DownloadManager
doesn't need to know which object will use it or any information about it. The only thing it cares about is that the class should conform to the delegate protocol, and that's it.
We mentioned before that classes, structures, and enumerations could adopt protocols. The difference among them is that classes are reference types, whereas structures and enumerations are value types. If you find yourself having some specific actions that will be done only via reference types, mark it as class
only. To do so, just mark it as follows:
protocol ClassOnlyProtocol: class{ // class only properties and methods go here }
Add a colon :
and the class
keyword to mark your protocol as class only.
It would be very useful to check whether an object conforms to a specific protocol or not. It's very useful when you have a list of objects, and only some of them conform to specific protocol. To check for protocol conformance, do the following:
class Rocket{ } var movingObjects = [Bicycle(name: "B1"), Car(name:"C1"), Rocket()] for item in movingObjects{ if let vehicle = item as? VehicleProtocol{ print("Found vehcile with name \(vehicle.name)") vehicle.move() } else{ print("Not a vehcile") } }
We created a list of objects, and some of them conform to VehicleProtocol
that we created earlier. Inside the for-loop
we casted each item to VehicleProtocol
inside if
statement; the cast will succeed only if this item already conforms to that protocol.
You see that when you list your properties and methods in a protocol, the type that conforms to that protocol should adopt to all properties and methods. Skipping one of them will lead to a compiler error. Some protocols may contain methods or properties that are not necessary to implement, especially with delegates. Some delegate methods are meant to notify you something that you don't care about. In that case, you can mark these methods as optional. The keyword optional
can be added before properties and methods to mark them as optional. Another thing, the protocol that has optional stuff should be marked with @Objc
. Take a look at the following example:
@objc protocol DownloadManagerDelegate { func didDownloadFile(fileURL: String, fileData: NSData) optional func didFailToDownloadFile(fileURL: String, error: NSError) }
It's the new version of DownloadManagerDelegate
, which marks didFailToDownloadFile
method as optional.
For its name, extensions are used to extend an existing functionality. In Swift, you can extend classes, structures, protocols, and enumerations. Extensions are similar to categories in Objective-C except that extensions don't have names. It's very useful to add functionality to any type that you don't have access to its source code, such as native classes String
, NSArray
, and so on.
In Swift, syntax is pretty easy, and that's why it is awesome. To extend any type, just type the following:
extension TypeToBeExtended{ }
Inside the curly braces, you can add your extensions to the type to be extended. In extension, you can do the following:
Adding instance- or class-computed properties
Adding instance or class methods
Adding new initializers
Defining subscripts
Adding nested types
Conforming to protocols
Once you create an extension to any type, the new functionality will be available for all instances in the whole project.
Create a new playground file in Xcode called
Extensions
.Create extension for double value by adding computing properties, as follows:
extension Double{ var absoluteValue: Double{ return abs(self) } var intValue: Int{ return Int(self) } } extension String{ var length: Int{ return self.characters.count } } let doubleValue: Double = -19.5 doubleValue.absoluteValue // 19.5 doubleValue.intValue // 19 extension Int{ func isEven() ->Bool{ return self % 2 == 0 } func isOdd() ->Bool{ return !isEven() } func digits() -> [Int]{ var digits = [Int]() var num = self repeat { let digit = num % 10 digits.append(digit) num /= 10 } while num != 0 return digits } } let num = 12345 num.digits() // [5, 4, 3, 2, 1]
In Double
type, we have added two computed properties. The computed properties are properties that will be calculated every time when it's called. We've added a property called absoluteValue
, which returns the absolute value; same for intValue
, which returns the integer value of double. Then, for any double value in the whole project, these two properties are accessible and can be used.
In the Int
type, we have defined three new instance methods. The isEven()
method should return true if this number is even, false otherwise, and the same logic applies for isOdd()
. The third method that has some more logic is digits()
, which returns array of digits in the number. The algorithm is simple; we get the last digit by getting the remainder of dividing the number by 10, and then skip the last digit by dividing by 10.
Extensions are not meant to add new properties and methods only. You extend types by adding new initializers, mutating methods, and by defining subscripts.
When you add instance methods, you can let them mutate (modify) the instance itself. In methods we've added before, we just do some logic and return a new value, and the instance value remains the same. With mutating, the value of instance itself will be changed. To do so, you have to mark your instance method with the mutating
keyword. Let's take a look at an example:
extension Int{ mutating func square(){ self = self * self } mutating func double(){ self = self * 2 } } var value = 8 value.double() // 16 value.square() // 256
When you mark your method as mutating
, it lets you to change self and assign new value to it.
Extensions allow you to add new initializer to the currently available initializer for any particular type. For example, let's take a look at the CGRect
class. CGRect
has three initializers: empty init
; init
with origin and size; and init
with x, y, width, and height. We will add new initializer with a center point and a rectangular size. Let's take a look at how to do it:
extension CGRect{ init(center:CGPoint, size:CGSize){ let x = center.x - size.width / 2 let y = center.y - size.height / 2 self.init(x: x, y: y, width: size.width, height: size.height) } } let rect = CGRect(center: CGPoint(x: 50, y: 50), size: CGSizeMake(100, 80)) // {x 0 y 10 w 100 h 80}
One of features that extensions provide to us is the ability to define subscripts to a particular type. Subscripting allows you to get value by calling [n]
to get information at index n. Like array, when you access item at that index, you can do the same with any type you want. In the following example, we will add subscripting support to the String
type:
extension String{ subscript(charIndex: Int) -> Character{ let index = startIndex.advancedBy(charIndex) return self[index] } } let str = "Hello" str[0] // "H"
To add subscript to type, just add the keyword subscript
followed by index
and the return type. In our preceding example, the subscript will return the character at a given index. We advanced the startIndex
, which is a property in the String
type and points to the first character by the input charIndex
. Then, we return the character at that Index
.
If you are coming from the old school where MRC (Manual Reference Counting) was being used for memory management, you definitely know how much headache developers suffer to manage memory in iOS. With iOS 5, Apple introduced ARC (Automatic Reference Counting), and life became easier in terms of memory management. Though ARC manages your memory automatically, some mistakes may ruin your memory with no mercy if you didn't understand the concept of memory management.
Before checking how to manage memory and avoid some common mistakes, I would like to highlight some notes:
Assigning a class instance to variable, constant, or properties will create a strong reference to this instance. The instance will be kept in memory as long as you use it.
Setting the reference to
nil
will reduce its reference counting by one (once it reaches zero, it will be deallocated from memory). When your class deallocated from memory, all class instance properties will be set tonil
as well.
Create two classes,
Person
andDog
, with a relation between them, as shown in the following code snippet (this code snippet has a memory issue called reference cycle):class Dog{ var name: String var owner: Person! init(name: String){ self.name = name } } class Person{ var name: String var id: Int var dogs = [Dog]() init(name: String, id: Int){ self.name = name self.id = id } } let john = Person(name: "John", id: 1) let rex = Dog(name: "Rex") let rocky = Dog(name: "Rocky") john.dogs += [rex, rocky] // append dogs rex.owner = john rocky.owner = john
Update the reference type of owner property in the
Dog
class to break this cycle:class Dog{ var name: String weak var owner: Person! init(name: String){ self.name = name } }
We have started our example by creating two classes, Person
and Dog
. The Person
class has one-to-many relation to the Dog
class via the property array dogs
. The Dog
class has one-to-one relation to class Person
via the property owner
. Everything looks good, and it works fine if you tested, but unfortunately we did a terrible mistake. We have a retain cycle problem here, which means we have two objects in memory; each one has a strong reference to the other. This leads to a cycle that prevents both of them from being deallocated from memory.
This problem is a common problem in iOS, and not all developers note it while coding. We call it as parent-child relation. Parent (in our case, it's the Person
class) should always have a strong
reference to child (the Dog
class); child should always have a weak
reference to the parent. Child doesn't need to have strong
reference to parent, as child should never exit when parent is deallocated from memory.
To solve such a problem, you have to break the cycle by marking one of these references as weak
. In step 2, we see how we solved the problem by marking the property owner as weak
.
The reference cycle problem can happen in situations other than relations between classes. When you use closure, there is a case where you may face a retain cycle. It happens when you assign a closure to a property in class instance and then this closure captures the instance. Let's consider the following example:
class HTMLElement { let name: String let text: String? lazy var asHTML: () -> String = { if let text = self.text { return "<\(self.name)>\(text)</\(self.name)>" } else { return "<\(self.name) />" } } init(name: String, text: String? = nil) { self.name = name self.text = text } } let heading = HTMLElement(name: "h1", text: "h1 title") print(heading.asHTML()) // <h1>h1 title</h1>
We have the HTMLElement
class, which has closure property asHTML
. Then, we created an instance of that class which is heading
, and then we called the closure to return HTML text. The code works fine, but as we said, it has a reference cycle. The instance set closure to one of its property, and the closure captures the instance (happens when we call self.name
and self.text
inside the closure). The closure in that case will retain self
(have a strong reference to the heading
instance), and at the same time, heading
already has a strong reference to its property asHTML
. To solve reference cycle made with closure, add the following line of code as first line in closure:
[unownedself] in
So, the class will look like this:
class HTMLElement { let name: String let text: String? lazy var asHTML: () -> String = { [unownedself] in if let text = self.text { return "<\(self.name)>\(text)</\(self.name)>" } else { return "<\(self.name) />" } } init(name: String, text: String? = nil) { self.name = name self.text = text } }
The unowned
keyword informs the closure to use a weak reference to self instead of the strong default reference. In that case, we break the cycle and everything goes fine.
In any iOS project, a lot of operations may fail and you have to respond to these errors in your project. Since Swift 2, a new mechanism has been added to the language for responding and dealing with errors in your project. You can now throw and catch errors when you do any operation that may fail for some reason. Suppose, you do some logic to request some data in a JSON format from a remote server and then you save this data in a local database. Can you imagine how many errors may happen for these operations? Connection may fail between your app and the remote server, failing to parse the JSON response, database connection is closed, database file doesn't exist, or another process is writing in database and you have to wait. Recovering from these errors allows you take the appropriate action based on the error type.
Before starting to learn how to handle errors in Swift, you first have to be familiar with how to represent in errors that are going to happen in your program. Swift provides you with a protocol called ErrorType
that your errors types should adopt. Then, to represent errors, here comes the role of enumerations to help you. You create a new enum, which lists all error cases, and this enum should conform to the ErrorType
protocol. The syntax of using enum with ErrorType
will be something like this:
enum DBConnectionError: ErrorType{ case ConnectionClosed case DBNotExist case DBNotWritable }
As we see it's pretty straightforward. You create enum representing the error that conforms to ErrorType
protocol, and then list all errors as cases in the enum.
As usual, let's create a new playground named
ErrorHandling
.Let's create now a new error type for a function that will sign up a new user in a system:
enum SignUpUserError: ErrorType{ case InvalidFirstOrLastName case InvalidEmail case WeakPassword case PasswordsDontMatch }
Now, create the sign up function that throws errors we made in the previous step, if any:
func signUpNewUserWithFirstName(firstName: String, lastName: String, email: String, password: String, confirmPassword: String) throws{ guard firstName.characters.count> 0 &&lastName.characters.count> 0 else{ throw SignUpUserError.InvalidFirstOrLastName } guard isValidEmail(email) else{ throw SignUpUserError.InvalidEmail } guard password.characters.count> 8 else{ throw SignUpUserError.WeakPassword } guard password == confirmPassword else{ throw SignUpUserError.PasswordsDontMatch } // Saving logic goes here print("Successfully signup user") } func isValidEmail(email:String) ->Bool { let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" let predicate = NSPredicate(format:"SELF MATCHES %@", emailRegex) return predicate.evaluateWithObject(email) }
Now, let's see how to use the function and catch errors:
do{ trysignUpNewUserWithFirstName("John", lastName: "Smith", email: "john@gmail.com", password: "123456789", confirmPassword: "123456789") } catch{ switch error{ case SignUpUserError.InvalidFirstOrLastName: print("Invalid First name or last name") case SignUpUserError.InvalidEmail: print("Email is not correct") case SignUpUserError.WeakPassword: print("Password should be more than 8 characters long") case SignUpUserError.PasswordsDontMatch: print("Passwords don't match") default: print(error) } }
We started our code example by creating a new error type called SignUpUserError
, which conforms to ErrorType
protocol. As we see, we listed four errors that may happen while signing up any user in our system, such as invalid first name or last name, invalid e-mail, weak password, and passwords that don't match. So far, so good!
Then, we create a function signUpNewUserWithFirstName
, which takes user input values, and as we can see, we have marked it with the throws
keyword. The keyword throws
says that this function may throw an error anytime during execution, so you be prepared to catch errors thrown by this method.
Inside the implementation of the function, you will see a list of guard
statements that checks for user input; if any of these guard
statements returned false
, the code of else
statement will be called. The statement throw
is used to stop execution of this method and throw the appropriate error based on the checking made.
Catching errors is pretty easy; to call a function that throws error, you have to call it inside the do-catch
block. After the do
statement, use the try
keyword and call your function. If any error happens while executing your method, the block of code inside the catch
statement will be called with a given parameter called error
that represents the error. We've created a switch
statement that checks the type of error
and prints a user-friendly statement based on the error type.
The information that we previously presented is enough for you to deal with error handling, but still there are a couple of things considered important to be known.
In the preceding example, you will notice that we've created a catch
statement, and inside, we used a switch
statement to cover all cases of error. This is a correct way, but for your reference, we have another way to do this. Consider the following:
catch SignUpUserError.InvalidFirstOrLastName{ } catch SignUpUserError.InvalidEmail{ } catch SignUpUserError.WeakPassword{ } catch SignUpUserError.PasswordsDontMatch{ }
After the do
statement, you can list catch
statement with the type of error that this statement will catch. Using this method has a condition that the catch
statements should be exhaustive, which means it should cover all types of errors.
Functions that usually throw an error, in some cases, don't throw an error. In some cases, you may know that calling a function like these with some kind of parameters will never throw an error. In that case, Swift gives you an option to disable error propagation via calling this method with try!
instead of try
. Calling throwing functions via try!
will disable error propagation, and if an error is thrown in that case, you will get a runtime error. So, it's better to take care while using try!
.
Generic code is used to write reusable and flexible functionalities that can deal with any type of variables. This helps in writing reusable and clean code regardless of the type of objects your generic code deals with. An example of using generics is when you use Array
and Dictionary
. You can create an array of Int
or String
or any type you want. That's because Array
is natively created and can deal with any type. Swift gives you the ability to write generic code very easily as you will see in this section.
Before learning how to write generic code, let's see an example of a problem that generics solve. I bet you are familiar with stack data structures and have been using it in one of the computer science courses before. Anyway, it's a kind of collection data structure that follows LIFO (Last in first out). It has very commonly used APIs for these operations, which are pop and push. Push inserts new item to the stack; pop returns the last inserted one. It's just a simple overview, as we will not explain data structures in this book as it's out of topic.
Here, we will create the stack data structure with/without generics:
Create a new playground named
Generics
.Let's create the data structure stack with type
Int
:class StackInt{ var elements = [Int]() func push(element:Int) { self.elements.append(element) } func pop() ->Int { return self.elements.removeLast() } func isEmpty()->Bool { returnself.elements.isEmpty } } var stack1 = StackInt() stack1.push(5) // [5] stack1.push(10) //[5,10] stack1.push(20) // [5,10,20] stack1.pop() // 20
Let's see the same created stack but with a generics fashion:
class Stack <T>{ var elements = [T]() func push(element:T) { self.elements.append(element) } func pop()->T{ return self.elements.removeLast() } } var stackOfStrings = Stack<String>() stackOfStrings.push("str1") stackOfStrings.push("str2") stackOfStrings.pop() var stackOfInt = Stack<Int>() stackOfInt.push(4) stackOfInt.push(7) stackOfInt.pop()
The first class we created, StackInt
, is a stack that can work only with the Int
type. It's good if you are going to use it with Int
type only. However, a famous data structure like it can be used with different types, such as String
or Double
. It's not possible to create different stack class for each type, and here comes the magic of generics; instead we created another class called Stack
marked with <T>
to say it's going to deal with the generic type T
, which can be Int
, String
, Double
, and so on. Then, we create two stack instances, stackOfStrings
and stackOfInt
, and both share the same code as their class is built with generics.