Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Reactive Programming with Swift 4
Reactive Programming with Swift 4

Reactive Programming with Swift 4: Build asynchronous reactive applications with easy-to-maintain and clean code using RxSwift and Xcode 9

Arrow left icon
Profile Icon Singh
Arrow right icon
€36.99
Paperback Feb 2018 320 pages 1st Edition
eBook
€20.98 €29.99
Paperback
€36.99
Subscription
Free Trial
Renews at €18.99p/m
Arrow left icon
Profile Icon Singh
Arrow right icon
€36.99
Paperback Feb 2018 320 pages 1st Edition
eBook
€20.98 €29.99
Paperback
€36.99
Subscription
Free Trial
Renews at €18.99p/m
eBook
€20.98 €29.99
Paperback
€36.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Table of content icon View table of contents Preview book icon Preview Book

Reactive Programming with Swift 4

Migrating from Swift 3 to Swift 4

This book aims to build on your current iOS development knowledge in Swift and gradually increase your Swift skills to master Reactive programming concepts in Swift. This book will guide you through the concepts while working with real-world apps and projects to give you a better understanding of RxSwift and related APIs.

Swift, as a programming language, has evolved many times over the years since its launch in 2014, and like any software update, we developers have to keep ourselves updated as well. We will start this book by giving you a hands-on update about what's new in Swift and how you can seamlessly migrate from your Swift 3 code to the latest Swift 4 syntax. You will then learn about Swift 4's new features and enhancements—from improvements in language syntax to the new protocols and APIs.

We will start with compatible Xcode IDE and how you can set up the environment required to work with the latest Swift release, some prerequisites before starting to migrate to the latest version, premigration preparation, things to do once the migration is complete, special cases, and other related stuff as we go through this chapter.

Unlike previous Swift releases, this release provides source compatibility with Swift 3 while working toward ABI stability. The main topics that will be covered in this chapter are as listed:

  • Setting up the Swift 4 environment
  • Changes/improvements to Swift
  • Additions to Swift
  • Migrating to Swift 4

What's new in Swift 4?

Swift 4 includes many changes; 21 proposals have been implemented to be specific, but we will only cover a subset of those. Around 10 of these relate to the Swift package manager and of the remaining 11, some of the changes are minor improvements, so we will cover the ones that you will encounter in your day-to-day work.

Application Binary Interface (ABI) is the specification to which independently compiled binary entities must conform to be linked together and executed.

Setting up the environment

There are a couple of ways to run Swift 4.

It's a prerequisite that you have a developer account and then you can use either of the mentioned methods:

  • Install Xcode 9, search for Xcode 9, log in with your developer account, and download the current beta available for downloads.
  • In case you prefer to use Xcode 8, you can use the latest development snapshot for Swift 4.0 available at Swift.org. Once the download finishes, open the package .pkg file and install the snapshot. Open Xcode and go to Xcode | Toolchains | Manage Toolchains. Now pick the recently installed Swift 4.0 Snapshot and restart Xcode IDE:

Now your projects or playgrounds will use Swift 4 while compiling. We will use Xcode 9 for writing and executing all the code in this book. At the time of writing, the current Xcode 9 is in beta release version 6.

In the subsequent sections, you will read about the new features available in Swift 4, how you can transition to the latest Swift version, that is, Swift 4, and what should be the strategy for switching a massive code base written in Swift 3 to Swift 4; however, before that, a word of caution- the language is still in beta, and we should expect some changes and bug fixes along the lines until the official release is announced. With that being said, there is nothing to worry about; to keep an eye on the changes and stay up to date with the new implementations and bug fixes, follow the official release notes.

What’s changed?

Before we go ahead and discuss the new additions, let’s see what has changed or improved in the existing language.

Changes/improvements in Dictionary

Many proposals were made to enhance the Dictionaries and make them more powerful. In certain scenarios, Dictionaries might behave in an unexpected manner, and for this reason, many suggestions were made to change the way Dictionaries currently work in certain situations.

Let’s take a look at an example. Filtering returns the same data type; in Swift 3, if you used a filter operation on a Dictionary, the return type of the result would be a tuple (with key/value labels) and not a Dictionary. Consider this example:

let people = ["Tom": 24, "Alex": 23, "Rex": 21, "Ravi": 43]
let middleAgePeople = people.filter { $0.value > 40 }

After the execution, you cannot use middleAgePeople["Ravi"] since the returned result is not a Dictionary. Instead, you have to follow the tuple syntax to access the desired value because the return type is tuple, middleAgePeople[0].value, which is not implicitly expected.

Thanks to the new release, the current scenario has now changed as the new return type is a Dictionary. This will break any existing implementation in which you had written your code based on the return type, expecting it to be a tuple.

Similarly, while working with Dictionaries, the map() operation never worked the way most developers expected, since the return type could be a single value while you passed in a key-value tuple. Let's look at the following example:

let ages = people.map { $0.value * 2 }

This remains the same in Swift 4, but there is the addition of a new method mapValues(), which will prove to be of more use as it allows values passed to the method to be transformed and spit out as a Dictionary with original keys.

For example, the following code will round off and convert all the given ages to Strings, place them into a new Dictionary with the exact same keys, that is, Tom, Alex, Rex, and Ravi:

let ageBrackets = people.mapValues { "\($0 / 10) 's age group" }

Mapping Dictionary keys is not safe as we might end up creating duplicates.

Grouping initializer

Grouping initializer is the new addition to the Dictionary that converts a sequence into a Dictionary of sequences grouped as per your ambition. Continuing our people example, we can use people.keys to get back an array of people names and then group them by their first letter, like this:

let groupedPeople = Dictionary(grouping: people.keys) { $0.prefix(1) }
print(groupedPeople)

This will output the following:

["T": ["Tom"], "A": ["Alex"], "R": ["Rex", “Ravi”]]

Here, T, A, and R are initializers to the distinct names. For instance, consider that you had one more name in the Dictionary, say "Adam" aged 55:

["Tom": 24, "Alex": 23, "Rex": 21, "Ravi": 43, "Adam": 55]

In this case, the groupedPeople array might look something like this:

["T": ["Tom"], "A": ["Alex", "Adam"], "R": ["Rex", “Ravi”]]

Alternatively, we can group people based on the length of their names, as shown:

let groupedPeople = Dictionary(grouping: people.keys) { $0.count }
print(groupedPeople)

This will output the following:

[3: ["Tom","Rex"], 4: ["Alex", "Ravi","Adam"]]

Key-based subscript with default value

To understand this change, let’s first try to cite why it was required in the first place; let's take a look at the following code example:

let peopleDictionary : [String: AnyObject] = ...
var name = "Unknown"
if let apiName = peopleDictionary["name"] as? String {
name = apiName
}

Basically, our goal is to get the name of the user from some Dictionary (probably coming from some API) and in case it doesn't exist, we just want to keep the default name.

There are two problems with that approach. The first is the fact that we've probably got more than just a name field, and we end up with repetitive "if let" statements that are basically just making our code less readable.

The second problem is that just for the sake of unwrapping a value, we need to come up with some artificial name for the temporary assignment (and hey, we are not good at naming stuff anyway).

So the question now is, can we do better?

The previous solution would be to use generics or extensions to modify the behavior of the existing libraries used to write some generic method to retrieve the desired value, but with Swift 4, it's now possible to access a Dictionary key and provide a default value to use if the key is missing:

let name = peopleDictionary["name", default: "Anonymous"]

We can write the same thing using nil coalescing; you can alternatively use Swift 3 to write this line:

let name = peopleDictionary["name"] ?? "Anonymous"

However, that does not work if you try to modify the value in the Dictionary rather than just reading it. Accessing the key in the Dictionary returns an optional rather than an exact value and for this reason, we can't modify a Dictionary value in place, but with Swift 4, you can write much more maintainable and succinct code, as follows:

var friends = ["Deapak", "Alex", "Ravi", "Deapak"]
var closeFriends = [String: Int]()
for friend in friends {
closeFriends[friend, default: 0] += 1
}

The preceding loop in code loops over each entry in the friends array and populates the count of each entry in the closeFriends Dictionary. Since we know that the Dictionary will always have a value, we can modify it in one line of code.

Convert tuples to Dictionary

With Swift 4, you can now create a new unique Dictionary from an array of tuples consisting of duplicate keys. Let's take an example of an array of tuples with duplicate keys:

let tupleWithDuplicateKeys = [("one", 1), ("one", 2), ("two", 2), ("three", 3), ("four", 4), ("five", 5)]

Also, you want to convert this array into Dictionary, so you can do this:

let dictionaryWithNonDuplicateKeys = Dictionary(tupleWithDuplicateKeys, uniquingKeysWith: { (first, _) in first })

Now if you try to print dictionaryWithNonDuplicateKeys;

print(dictionaryWithNonDuplicateKeys), the output will be as illustrated:

["three": 3, "four": 4, "five": 5, "one": 1, "two": 2],

This is along with all the duplicate keys removed in the resulting Dictionary.

Convert arrays to Dictionary

You can create a new Dictionary by mapping two sequences one is to one or by mapping a sequence of keys and values according to a custom logic; let’s take a look at both the methods:

  • Mapping two sequences (arrays) one is to one: Consider that you have two sequences personNames and ages as shown here:
 let personNames = ["Alex", "Tom", "Ravi", "Raj", "Moin"]
let ages = [23, 44, 53, 14, 34]

You can create a Dictionary contacts by joining these two arrays, as follows:

let contacts = Dictionary(uniqueKeysWithValues: zip(personNames, ages)) 

The output will be this:

["Tom": 44, "Raj": 14, "Moin": 34, "Ravi": 53, "Alex": 23]
  • Create a new Dictionary by mapping an array of keys and values according to a custom logic. Suppose you have two arrays- one with Strings representing all the odd numbers in words and other one with integers from 1 to 10:
let oddKeys = ["one", "three", "five", "seven", "nine"]
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • Now, consider that you want to create a Dictionary in which you want to map the String values to corresponding int values; you can do this as follows:
numbers = numbers.filter { $0 % 2 != 0 }
let oddDictionary = Dictionary(uniqueKeysWithValues: zip(oddKeys, numbers))
print(oddDictionary)
  • The output will be this:
["six": 6, "four": 4, "eight": 8, "ten": 10, "two": 2]

Easy, isn’t it!

Resolving duplicates

Swift 4 allows us to initialize a Dictionary from a sequence with duple existence of entries and manage the duplicates easily. Suppose you have an array of friends as follows:

var friends = ["Deapak", "Alex", "Ravi", "Deapak"]

Also suppose that you want to create a Dictionary with all the friends, remove duplicates, and just maintain the count of the number of occurrences that occurred in the initial friends array; you can do this by initiating a new Dictionary, as follows:

let friendsWithMultipleEntries = Dictionary(zip(friends, repeatElement(1, count: friends.count)), uniquingKeysWith: +)

The output will be the following:

["Deapak": 2, "Ravi": 1, "Alex": 1], 

This helps you avoid overwriting key-value pairs, without putting in a word. The preceding code besides the shorthand +, uses zip to fix duplicate keys by adding the two contrasting values.

zip(_:_:) creates a sequence of pairs built out of two underlying sequences.

Reserving capacity

Dictionary and sequence now have the capacity to explicitly, unambiguously reserve capacity.

Suppose you have a sequence of friends with an initial capacity of 4:

friends.capacity  // 4

You can now reserve the capacity by doing this:

friends.reserveCapacity(20)

This reserves a minimum of 20 segments of capacity:

friends.capacity // 20

Reallocating memory to objects can be an expensive task, and if you have an idea about how much space it will require to store an object, then using reserveCapacity(_:) can be an easy and simple way to increase performance.

Swift 4 brings in a number of modifications to the Dictionary, 12 to be exact as per the official Apple developers guide, and a number of additions that we will discuss in subsequent sections:

Changes/improvements in Strings

Undoubtedly, the String is one of the majorly used data types in all the programming languages. Apparently, it is the data type that mankind understands better. Strings are important to the extent that they have the ability to significantly change our perception of how difficult or simple it is to learn a programming language. Hence, it becomes really important to follow any development to this data type. Strings received a major overhaul with Swift 4, making them collections of characters. In the earlier versions, several times, Swift, with its complicated way of handling subStrings and characters, went overboard in advocating accuracy over convenience.

Bid bye to string.characters

As part of the changes, this is one of the most welcomed changes. This change eliminates the necessity for a characters array on String, which means now you can reverse them, loop over them character-by-character, map() and flatMap() them, and more than anything, you can now iterate directly over a String object:

let vowels = "AEIOU"
for char in vowels {
print(char)
}

This prints the following:

 A , E , I , O, U

Here, you not only get logical iteration through String, but also specific understanding for collection and sequence:

vowels.count , result is 5, no need of vowels.characters.count
vowels.isEmpty , result is false
vowels.dropFirst() , result is "EIOU"
String(vowels.reversed()) , result is "UOIEA"

There is a small improvement to the way characters behave—now you can obtain the UnicodeScalarView straight from the character, whereas earlier, instantiation of a new String was needed.

String protocol

Back in the days of Swift 1, Strings were a collection. In Swift 2, collection conformance was dropped because some of the behavior was thought to differ strongly enough from other collection types. Swift 4 reverses this change, so Strings are collection types again. One of the examples was described in the previous section where you were able to traverse over String vowels just like a normal array. In Swift 3, despite not being a collection, you could perform slicing operations on a String. Slicing a String in Swift 3 returned a String as well. This String was a String's own SubSequence, which led to some memory issues and one of the bigger changes in Swift 4 is the introduction of the subString types to remove these issues. For example, consider that we do this:

let secondIndex = vowels.index(after: vowels.startindex)
let subString = vowels[secondIndex...]

On doing this, if you inspect the type of subString, you will notice that it is String.SubSequence and not a String. With the existence of two types of String and SubSequence for adding functionality to Strings in your code base, you have to extend both types individually, which is quite cumbersome. Let's take a look at the following example:

We will add an extension to the Character type to determine whether a character is in uppercase:

extension Character {
var isUpperCase : Bool {
return String(self) == String(self).uppercased()
}
}

Using this, let's define a stripped uppercase method on String:

extension String {
func strippedUppercase() -> String {
return self.filter({ !$0.isUppercase})
}
}

So now that we have this method, we can use it on a String. So we can say that vowels.strippedUppercase() will return an empty String since all the characters in the vowels String are already uppercase.

If we grab a slice of the String though, that is, subString that we got earlier in the execution and use subString.strippedUppercase(), we get an error as subString is not a String anymore.

Does this mean that we need to extend the subString type and add this strippedUppercase() method as well? Thankfully NO!

Swift 4 also introduces String protocol. Both String and subString affirms to this new String protocol type. So anywhere we use extend String in our code base, we should now extend String protocol instead to ensure that subString gets the same behavior. So let's move the strippedUppercase() method into an extension of String protocol:

extension StringProtocol {
func strippedUppercase() -> String {
return self.filter({ !$0.isUppercase})
}
}

When we do this, we get an error because we need to be aware of what self means inside the method; self can now mean either a String or subString. To ensure that we always account for this, we will always convert self, make it a String instance, and then do the work we need. So if self is already a String, nothing happens and the function does not throw an error, but if it is a subString, we will make it a String and then call filter, and the preceding function works just fine:

extension StringProtocol {
func strippedUppercase() -> String {
return String(self).filter({ !$0.isUppercase })
}
}

There are more changes in String, but this should be the most used part that we might use from day to day.

Changed interpretation of grapheme clusters

An additional big advancement is the way String interprets grapheme clusters. Conformity of Unicode 9 gives resolution to this.

The use of extended grapheme clusters for character values in Swift 4 means that concatenation and modification of Strings may cause no affect on a resulting String's character count.

For example, if you append a COMBINING ACUTE ACCENT (U+0301) to the end of the String initialized to "cafe", the resulting String will have a character count of 4, and the fourth character will be "e", not e':

var word = "cafe"
print("total chars in \(word) is \(word.count)")

It prints "total chars in cafe is 4":

word += "\u{301}"    // COMBINING ACUTE ACCENT, U+0301
print("totalchars in \(word) is \(word.count)")

It prints "total chars in café is 4", whereas the count would increase by 1 to reflect 5 as a result of print statement earlier.

Sequence of one or more Unicode scalars that when combined generate a single human-readable character is known as an extended grapheme cluster.

Similar to Dictionaries, the total number of modifications made to String API can be summed up by the following image:

Access modifiers

The fileprivate access control modifier was used in Swift 3 to make important data visible outside the class in which it was declared but within the same file. This is how it all works in the case of extensions:

class Person {
fileprivate let name: String
fileprivate let age: Int
fileprivate let address: String
init(name: String, age: Int, address: String) {
self.name = name
self.age = age
self.address = address
}
}

extension Person {
func info() -> String {
return "\(self.name) \(self.age) \(self.address)"
}
}

let bestFriend = Person(name: "Robert", age: 31)
bestFriend.info()

In the preceding code, we created an extension for the Person class and accessed its private properties in the info() method using String interpolation. Swift encourages the use of extensions to break code into logical groups. In Swift 4, you can now use the private access level instead of fileprivate in order to access class properties declared earlier, that is, in the extension:

class Person {
private let name: String
private let age: Int
private let address: String
init(name: String, age: Int, address: String) {
self.name = name
self.age = age
self.address = address
}
}
extension Person {
func info() -> String {
return "\(self.name) \(self.age) \(self.address)"
}
}
let bestFriend = Person(name: "Robert", age: 31)
bestFriend.info()

These were all the changes introduced in Swift 4. Now we will take a look at the new introductions to the language.

What's new

In the next section, we will discuss new additions to the existing libraries and functionalities available in Swift.

JSON encoding and decoding

Everyone's favorite change to Swift 4 is of course the latest way to parse JSON. If you have been part of the Swift community for a while now, you'll know that every month we have a new hot way to parse JSON or so it feels, and now finally, we have an official way, so let's take a look. Let's talk about the Why first; Swift didn't ship with any native archival or serialization APIs and instead benefited from the Objective-C implementations available to it. While this allowed us to achieve certain end goals, it was both restrictive in that only NSObject subclasses can benefit, and we had to implement solutions for value types and as always, the existing solutions, NSJSONSerialization and so on, are far from Swift like.

The goal, therefore, for this proposal was to allow native archival and serialization of Swift Enums and Structs and to do that in a type safe way. Let's introduce some sample JSON to our playground to see how it works in practice and as an added benefit, we get to work with Swift 4's multiline String literal syntax:

import Foundation
let exampleJson = """
{
"name": "Photography as a Science",
"release_date": "2017-11-12T14:00:00Z",
"authors": [
{
"name": "Noor Jones"
},
{
"name": "Larry Page"
}
]
}
"""

We cannot convert this raw JSON in a datatype, so let's say as follows:

let json = exampleJson.data(using: .utf8)!

Now, let's define a type, and we will keep it simple so that we can see how the new API works:

struct Book {
let name: String
}

We want to decode the JSON into an instance of this struct Book and doing that in Swift 4 is super easy. First, we will make our model conform to our new Codable protocol, after which all we need to do is the following:

struct Book: Codable{
let name: String
}
let photographyBook = try! JSONDecoder().decode(Book.self, from: json)

If we match the values on the instance, we can see that they match the value in the JSON data and that's it, easy isn't it?

Multiline String literals

With earlier versions of Swift, you had to use \n in your Strings to add line breaks, which meant if the String was very long, then your code would start looking ugly with heaps of \n sprinkled across it. Proposal SEO163 introduces multiline literals to Swift with a very simple syntax. Long Strings or multiline Strings are Strings delimited by triple quotes, that is, """ so we can say as follows:

let paragraph = """
This is a paragraph to demonstrate an example of multi-line String literals and the use in the latest Swift 4 syntax!
"""

So you have to end the multiline String literals with triple quotes as well, as shown in the preceding code. The nice part about these multiline String literals is that they can contain newlines, single quotes, nested, and unescaped double quotes without the need to escape them. As an example, you can include some sample JSON to test against without escaping every single quote.

Smart key paths

Another important change introduced by Swift 4 is that of smarter key paths. Swift key paths are strongly typed and enforce a compile time check and remove a common runtime error.

You write a key path by starting with a backslash: `\Book.title`. Every type automatically gets a `[keyPath: …]` subscript to get or set the value at the specified key path:

struct Book {
var title = ""
let price : Float
}
let titleKeyPath = \Book.name
let mathsBook = Book(name: "Algebra", price: 10.50)
mathsBook[keyPath: titleKeyPath]

The value in the earlier mentioned keyPath is "Algebra".

The titleKeyPath object defines a citation to the name property. Then, it can be used as a subscript on that object. You can store and manipulate key paths. For example, you can append additional segments to a key path to drill down further. Key paths are composed of a root, and then you can drill down by following a combination of properties and subscripts.

If you change the variable of mathsBook from let to var, a specific property can also be modified through the keyPath subscript syntax:

mathsBook[keyPath: titleKeyPath] = "Trigonometry"
let newTitle = mathsBook[keyPath: titleKeyPath]

The value in the mentioned keyPath is "Trigonometry".

One sided ranges

Swift 4 makes it optional to provide a starting index or finishing index of ranges, as used with earlier versions of Swift.

With earlier versions of Swift, you had to do the following to use ranges:

let contactNames = [“Alex”, “Ravi”, “Moin”, “Vlad”, “Mark”]
let firstTwoContacts = contactNames[0..<2]
let lastThreeContacts = contactNames[2..<contactNames.count]
print(firstTwoContacts)
print(lastThreeContacts)

You will get the result as follows:

["Alex", "Ravi"] , for [0..<2]
["Moin", "Vlad", "Mark"], for [2..<contactNames.count]

However, with Swift 4, you no longer have to be constrained to lower bounds or upper bounds of the range mentioned in the for loop mentioned earlier in the code example. You can now use a one sided range where the missing side will automatically be treated as the start or end of a sequence:

let firstTwoContacts = contactNames[..<2]
let lastThreeContacts = contactNames[2...]
print(firstTwoContacts)
print(lastThreeContacts)

You will get the result as shown:

["Alex", "Ravi"] , for [..<2]
["Moin", "Vlad", "Mark"] for [2...]

Pattern matching with one sided ranges.

Pattern matching works really well with one sided ranges in switch statements, but you should be mindful of the one hitch that it has.

While writing a switch case, be careful to add a default case since you have to make your switch case exhaustive and since one sided ranges are infinite now, adding a default case becomes mandatory:

let selectedNumber = 7
switch selectedNumber {
case ..<0 :
print("You have selected a negative number.")
case 0... :
print("You have selected a positive number")
default :
break
}

Here, note that we have already covered all the scenarios in the first 2 cases:

  • Case 1: All negative numbers up to -1
  • Case 2: All positive numbers from 0 onward

Hence, we simply break out the switch statement in the default case.

swap versus swapAt

The swap(_:_: ) method in Swift 3 works on "pass by reference principle" and swaps two elements of a given array on the spot. In pass by reference, actual memory addresses are used rather than values:

var integerArray = [1, 2, 4, 3, 5]
swap(integerArray [2], integerArray [3])

As you can see, the parameters are passed as in out parameters, which means the actual references or placeholder addresses are accessible directly inside the function. On the other hand, Swift 4’s swapAt(_:_:) works on “pass by value” principle and only the corresponding indices are passed to the function to be swapped:

integerArray.swapAt(2, 3)

The swap(_:_:) function will not be seen in Swift 4, because it will be deprecated and removed, and you have a couple of approaches to replace it. The first approach uses a temporary constant as follows:

let temp = a
a = b
b = temp

The second takes advantage of Swift's built in tuples, as follows:

(b, a) = (a, b)

Improved NSNumber

With earlier versions of Swift, behavior of NSNumber might be unexpected and casting to Uint8 might result in absurd results:

let number1 = NSNumber(value: 1000)
let number1ConvertedToUInt = number1 as? UInt8

In this scenario, logically, the value inside number1ConvertedToUInt should be nil, but this was not the case and the value would be 1000% 255, that is, 232 instead. This is because the maximum value that a UInt can hold is 255. Fortunately, this behavior has been resolved in Swift 4 and now if you execute the same code in Swift 4, you should expect the value of number1ConvertedToUInt to be nil.

Directly access unicode scalars of characters

Swift 4 allows direct access to unicode scalars associated with characters:

let character: Character = “A”
let unicodeScalar = character.unicodeScalars

Done! Easy, isn’t it? Before you would have to convert the character to a String first and then try to access unicode scalar.

Migrating to Swift 4

As opposed to the previous releases of Swift, transitioning from Swift 3 to Swift 4 is less cumbersome when compared to the earlier migrations. The Swift migration tool is now bundled right into Xcode and is capable of handling most of the changes autonomously. Let's cover the steps required to update the version of a code base to the latest Swift release.

Preparation before migration

Ensure that the project that you are migrating builds successfully in Swift 3.2 mode, and all its tests pass. Keep in mind that Swift 3.2 does have significant changes from 3.1 as well as the SDKs against which you built, so you may need to resolve errors initially.

It’s highly recommended that you manage your project under source control. This enables you to easily review the applied changes via the migration assistant, get rid of them, and retry the migration if required.

Different from last year, the migrator is built directly into the compiler and not a separate tool, so it can work with both the versions of Swift, that is, 3.2, and 4.

Swift migration assistant

If you open your project with Xcode 9 for the first time, you will see a migration opportunity item in the Issue Navigator; click on it to activate a sheet asking you if you'd like to migrate. You can be reminded later or invoke the migrator manually from the menu—Edit | Convert | To Current Swift Syntax…

You will be given a list of targets to migrate. Only those targets that contain Swift code will be selected.

There is only one migration workflow this year, although there is a choice between two kinds of @objc inference:

  • Minimize inference: Add an @objc attribute to your code only where it is needed based on static inference. After using this option, you need to follow the manual steps.
  • Match Swift 3 behavior: Add an @objc attribute to your code anywhere it would be implicitly inferred by the compiler. This option does not change the size of your binary as it adds explicit @objc attributes everywhere.

Clicking on Next will bring up the Generate Preview sheet and a migration build will be initiated by the assistant to get source changes. Once this is completed, you will be shown all the changes that will be applied when you click on Save. This will also change the Swift language version build setting for the migrated targets to Swift 4.

You may find some issues while processing the targets during the migration process. You can check the log for these errors by switching to report navigator and converting the entry that was added.

Swift 4 migration changes overview

Extensive changes that the migrator suggests occur from data produced by a comparison of the previous SDK and the current SDK, which may drive renaming of identifiers and types, for example; and from normal compiler fix-its. There are some special arrangements where the migrator can safely perform simple mechanical changes.

SDK changes

Moving global constants into static type properties and converting String constants into Swift enumeration cases are the two most common SDK changes. Migrator handles these automatically. You’ll also see various type signature changes.

Notable special cases

The new release has many changes and additions, but there are some special cases that are worth mentioning. In the upcoming sections, we will cover some of these special cases.

New String

New APIs are added to String in Swift 4; the return types will be String or subString in certain cases. To ease this transition, the migrator will assist by adding explicit initializers in places where the API expects special cases.

We have already discussed some important changes in the String API earlier in the chapter.

Differentiating between single-tuple and multiple-argument function types

f: (Void) -> ()

When using f: (Void) -> () for the type of a function argument, it is generally meant to be f: () -> (), so the migrator will suggest that you use this type instead. Otherwise, with the new rules in SE-0110 for Swift 4, you will need to call the f function as f(()).

To read more about the Swift proposals, you can visit https://Apple.github.io/swift-evolution/.

Adding tuple destructuring

Consider code such as the following:

swift func foo(_: ((Int, Int) -> ()) {} foo { (x, y) in print(x + y) }

The migrator must add explicit tuple destructuring to continue building in Swift 4, such as shown here:

swift func foo(_: ((Int, Int) -> ()) {} foo { let (x, y) = $0; print(x + y) }

Default parameter values must be public

The compiler now checks accessibility of referenced objects a bit more strictly; non-literal values that you want to use in public functions as arguments should also be public. Among other things, this exposes an opportunity for optimizing access to the value at the call site. As this may involve API design, the migrator does not suggest fixes, although there are some possibilities for you to consider as an API author:

  • Making the referenced default values public
  • Providing public functions that return a sensible default value

In both cases, consider the impact of exposing a new API, ensuring that you document your public symbols.

After migration

After applying the migrator changes, you might need to do some manual changes in order to build the project.

Some compiler errors might have some fixits; Xcode suggests these fixits and most of them are applied already by the migrator, but if the fixit does not fit almost 100% in the given scenario, then you might need to do it manually.

It is not necessary that the code that the migrator supplies is ideal, even if it compiles correctly. Use your best judgement and check that the changes are appropriate for your project.

Known migration issues

With any beta release of Xcode, numerous bugs get reported and with iterative releases of the beta versions for IDE, these bugs keep reducing. Similarly, there are some known issues with the current beta version of Xcode, and they will be fixed in the upcoming releases. At the time of writing this chapter, the Xcode IDE version is 9 beta 6, and mentioning all the known issues with the current version of IDE might change quite a lot in a few months, so it is better to follow the official release notes provided by Apple that are released with every IDE release in order to stay up to date with the latest known issues.

Using Carthage/CocoaPods projects

Here are some important points to consider when migrating a project with external dependencies using package managers such as Carthage, CocoaPods, or the Swift package manager:

  • It is recommended to use source dependencies rather than binary Swift modules, because Swift 3.1 modules will not be compatible with Swift 3.2/4 modules unless you can get distributions that were built in Swift 3.2 or Swift 4 mode
  • Ensure that your source dependencies work smoothly with Swift 3.2 as well as your own targets
  • You need to remove Carthage file's search path or clean the build folder if you have used Carthage in your project
  • It is not necessary to migrate your source dependencies as long as they can build in Swift 3.2 mode

Summary

Swift is a fairly new language, and the Apple developers keep updating the underlying APIs and language syntax while enhancing the language features by adding new APIs. In this chapter, we learned about the changes and additions to Swift with its latest release, that is, Swift 4. We covered how to migrate our current IDE to support the latest Swift release, and then we went ahead and covered major changes to the existing APIs, followed by the new additions to the language. We highlighted the major changes that you will encounter most in your day-to-day programming practices. Toward the end of the chapter, we also covered how to migrate an existing code base to Swift 4 and tackle some of the issues that you might come across while trying to update the code base. This book is more about Reactive programming, so we will start working with Reactive concepts from Chapter 2, FRP Fundamentals, Terminology, and Basic Building Blocks, onward, but since we will be working with Swift 4 throughout the book, it made sense to start by getting you up to date with the development language; next up will be the setup of the overall development environment.

Left arrow icon Right arrow icon

Key benefits

  • Build fast and scalable apps with RxSwift
  • Apply reactive programming to solve complex problems and build efficient programs with reactive user interfaces
  • Take expressiveness, scalability, and maintainability of your Swift code to the next level with this practical guide

Description

RxSwift belongs to a large family of Rx implementations in different programming languages that share almost identical syntax and semantics. Reactive approach will help you to write clean, cohesive, resilient, scalable, and maintainable code with highly configurable behavior. This book will introduce you to the world of reactive programming, primarily focusing on mobile platforms. It will tell how you can benefit from using RxSwift in your projects, existing or new. Further on, the book will demonstrate the unbelievable ease of configuring asynchronous behavior and other aspects of the app that are traditionally considered to be hard to implement and maintain. It will explain what Rx is made of, and how to switch to reactive way of thinking to get the most out of it. Also, test production code using RxTest and the red/ green approach. Finally, the book will dive into real-world recipes and show you how to build a real-world app by applying the reactive paradigm. By the end of the book, you’ll be able to build a reactive swift application by leveraging all the concepts this book takes you through.

Who is this book for?

This book is for the developers who are familiar with Swift and iOS application development and are looking out to reduce the complexity of their apps. Prior experience of reactive programming is not necessary.

What you will learn

  • Understand the practical benefits of Rx on a mobile platform
  • Explore the building blocks of Rx, and Rx data flows with marble diagrams
  • Learn how to convert an existing code base into RxSwift code base
  • Learn how to debug and test your Rx Code
  • Work with Playgrounds to transform sequences by filtering them using map, flatmap and other operators
  • Learn how to combine different operators to work with Events in a more controlled manner.
  • Discover RxCocoa and convert your simple UI elements to Reactive components
  • Build a complete RxSwift app using MVVM as design pattern
Estimated delivery fee Deliver to Ireland

Premium delivery 7 - 10 business days

€23.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Feb 27, 2018
Length: 320 pages
Edition : 1st
Language : English
ISBN-13 : 9781787120211
Vendor :
Apple
Category :
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Estimated delivery fee Deliver to Ireland

Premium delivery 7 - 10 business days

€23.95
(Includes tracking information)

Product Details

Publication date : Feb 27, 2018
Length: 320 pages
Edition : 1st
Language : English
ISBN-13 : 9781787120211
Vendor :
Apple
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 106.97
Hands-On Full-Stack Development with Swift
€36.99
Machine Learning with Swift
€32.99
Reactive Programming with Swift 4
€36.99
Total 106.97 Stars icon

Table of Contents

14 Chapters
Migrating from Swift 3 to Swift 4 Chevron down icon Chevron up icon
FRP Fundamentals, Terminology, and Basic Building Blocks Chevron down icon Chevron up icon
Set up RxSwift and Convert a Basic Login App to its RxSwift Counterpart Chevron down icon Chevron up icon
When to Become Reactive? Chevron down icon Chevron up icon
Filter, Transform, and Simplify Chevron down icon Chevron up icon
Reduce by Combining and Filtering and Common Trade Offs Chevron down icon Chevron up icon
React to UI Events – Start Subscribing Chevron down icon Chevron up icon
RxTest and Custom Rx Extensions – Testing with Rx Chevron down icon Chevron up icon
Testing Your RxCode – Testing Asynchronous Code Chevron down icon Chevron up icon
Schedule Your Tasks, Don't Queue! Chevron down icon Chevron up icon
Subscribe to Errors and Save Your App Chevron down icon Chevron up icon
Functional and Reactive App-Architecture Chevron down icon Chevron up icon
Finish a Real-World Application Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela