Errata: May 6, 2019
Some changes have been made in order to compile with Swift SDK upgrades.
Please post errors not listed below in the LiveBook Errata thread. Thank you for purchasing iOS Development with Swift.




Chapter 1, Figure 1.5, (p9)

Organization identifier should be com.interactivecoconut

Chapter 1, 1.5.4, (p23)

Replace

"…such as rotating the device, shaking the device, or tapping the device's Home button."

with:

"…such as rotating the device or shaking the device."

Chapter 2, 2.2, first paragraph (p35)

In two places, replace:

"qantity"

with:

"quantitySoup"

Chapter 2, 2.3.3, Step 3, (p38)

Remove the following two sentences because the merge method was introduced in Swift 4:

"Concatenating two dictionaries is, strangely, not available in Swift. In the next chapter, you'll add this functionality to Swift by extending the Dictionary type."

Chapter 3, 3.1, Listing 3.1, (p61)

Change from:

static let feetPerKm:Double = 5280

to:

static let feetPerKm:Double = 3280.84

Chapter 3, Listing 3.3, (p66)

Line of code that reads:

class landline:Telephone {

should have a capital L:

class Landline:Telephone {

Chapter 3, 3.3, Step 3, (p76)

Change from:

"Extensions can add computed properties, but can't add stored properties."

to:

"Extensions can add computed properties, but can't add stored instance properties."

Chapter 3, 3.3.1, Step 3, (p76)

Change from:

"Add a feet computed property."

to:

"Add a feet stored type property."

Chapter 3, 3.3.2, Step 3, (p77)

Replace the following text:

"As you saw in the previous chapter, the dictionary doesn't contain a method to join with another dictionary. Let's rectify this situation!"

with:

"In Swift 4, a new method was introduced to merge two dictionaries, but I think the syntax is a little unwieldy. Let's rectify the situation!"

Chapter 3, 3.3.3, Step 1, (p78)

"Redefine the add method in a Dictionary extension as an overloading of the + operator."

Add the following sentence: "Be sure to overload the operator outside of the Dictionary extension."

Chapter 5, 5.1.2, "Connecting actions from code," (p113)

Remove point 3.

Chapter 5, 5.2.3, "The responder chain" (p117)

Change:

"...it passes this event up to its super-class..."

to:

"...it passes this event up to its super-view..."

Chapter 5, 5.3, Step 2, (p120)

Change:

"Select Copy items, if needed"

to:

"Select Copy items if needed"

Chapter 5, 5.3.1, Step 1, (p122)

Change:

"If you want your pan to only respond to only one- or two-finger pans..."

to:

"If you want your pan to only respond to one or two-finger pans..."

Chapter 7, Lazy stored property (p173, p174)

Change:

lazy var lettersUpper:String = self.letters.uppercased()

to:

lazy var lettersUpper = letters.uppercased()

Change:

"Notice four additional factors:"

to:

"A couple of points about lazy stored properties:"

Remove these two bullet points:

  • Lazy stored properties based on other instance properties or methods need to specify the self keyword first.
  • To assist the compiler to infer the type of lazy stored properties based on other instance properties, you'll need to explicitly type the variable.
  • Chapter 7, 7.1.2, Step 2, (p177)

    Change:

    "Select the File Inspector for the main storyboard."

    to:

    "Select the File Inspector for the main storyboard and click anywhere in the canvas."

    Chapter 7, 7.2.4 "Nested stack views in Interface Builder," Step 6 (p193)

    Change:

    "Because the text view has an intrinsic content height of its contents..."

    to:

    "Because the text view doesn't have an intrinsic content height..."

    Chapter 8, 8.3 "Observing keyboard notifications," (p205)

    Change:

    "...and you need to know the size of the..."

    to:

    "...and you need to know the position of the..."

    Also change:

    "...about the keyboard, such as its size."

    to:

    "...about the keyboard, such as its position."

    Chapter 8, 8.3.1 "What is a notification" TIP (p205)

    Replace: "UIKeyboardWillChangeFrame" with "keyboardWillChangeFrameNotification"

    Chapter 8, 8.3.2 "Observing a keyboard frame change notification" point 2 (p207)

    In code block, replace:

    NSNotification.Name.UIKeyboardWillChangeFrame

    with:

    UIResponder.keyboardWillChangeFrameNotification

    Chapter 8, 8.3.4 "Extracting keyboard information from the notification," (p208, 209)

    Dot point 1, change:

    UIKeyboardFrameEndUserInfoKey

    to:

    UIResponder.keyboardFrameEndUserInfoKey

    Dot point 2, change:

    UIKeyboardAnimationDurationUserInfoKey

    to:

    UIResponder.keyboardAnimationDurationUserInfoKey

    Dot point 3, change:

    UIKeyboardAnimationCurveUserInfoKey

    to:

    UIResponder.keyboardAnimationCurveUserInfoKey

    Code block in point 1, change:

    var keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey]

    to:

    let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]

    Remove point 2

    "To make things more complicated..."

    Renumber points 3 and 4 to points 2 and 3.

    Dot point 4, code block, change:

    guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] 
            as? Double,
      curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey]
        as? UInt
      else { return }

    to:

    guard let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] 
            as? Double,
      curve = userInfo[UIKeyboardAnimationCurveUserInfoKey]
        as? UInt
      else { return }

    Chapter 8, 8.3.6 "Calculating the offset to animate," (p210)

    After:

    "...and adding in a five-point margin."

    Add:

    "We'll come back to this top constraint in a moment."

    Chapter 8, 8.4.1 "Animating the view from under the keyboard" point 2 (p212)

    In both the text and the code block, change:

    UIViewAnimationOptions

    to:

    UIView.AnimationOptions

    Chapter 8, 8.6 "Summary" Second dot point (p224)

    Replace: "UIKeyboardWillChangeFrame" with "keyboardWillChangeFrameNotification"

    Chapter 9, 9.1.2 "Set up the Model," (p240)

    Change:

    "Great, you can now use this Book class..."

    to:

    "Great, you can now use this Book struct..."

    Chapter 9, 9.1.2 "Creating a Books Manager" (p240)

    Code block in point 1, change:

    private lazy var books: [Book] = self.loadBooks()

    to:

    private lazy var books = loadBooks()

    Chapter 9, 9.2.1 "Embedding a navigation controller," step 2 (p244)

    Change:

    "Double-click in the middle of the navigation bar to open the edit title field and give it the title Books."

    to:

    "Select the navigation bar, open the attributes inspector, and give the scene the title Books."

    Chapter 9, 9.2.1 "Embedding a navigation controller," Step 3, (p244)

    Change:

    "..Find Navigation Bar Item in the Object Library...."

    to:

    "..Find Bar Button Item in the Object Library...."

    Chapter 9, 9.2.4 "Using your delegate protocol," Step 1,2 (p251)

    Change four references to "destinationViewController" to "destination"

    Chapter 9, 9.5 "Deleting a row" Step 2 code block (p261)

    Replace:

    UITableViewCellEditingStyle

    With:

    UITableViewCell.EditingStyle

    Chapter 10, 10.2.1 "Creating a search controller," Step 3, (p271)

    Change:

    "Turn this off, too: searchController.definesPresentationContext = true "

    to:

    "Turn this on: definesPresentationContext = true "

    Chapter 10, 10.2.4 "Removing a row with filtered data" Step 2, (p276)

    Change:

    guard let bookIndex = books.index(of: removedBook) else {

    to:

    guard let bookIndex = books.firstIndex(of: removedBook) else {

    Chapter 10, 10.2.4 "Updating a row with filtered data" (p277)

    Change:

    guard let bookIndex = books.index(of: bookToUpdate) else {

    to:

    guard let bookIndex = books.firstIndex(of: bookToUpdate) else {

    Chapter 10, Figure 10.17 "Alternative solutions for sharing data," (p291)

    Dependency injection arrows should go in the reverse direction.

    Chapter 11, 11.2.3 "Adopting Codable Protocol," Step 1, (p313)

    Change:

    class Book: Codable {

    to:

    struct Book: Codable {

    Chapter 11, 11.2.4 "Adding, updating and removing books," Step 3, (p321)

    Change:

    book.id = Int(db.lastInsertRowId())

    to:

    book.id = Int(db.lastInsertRowId)

    Chapter 11, 11.2.4 "Retrieving books from the database," Step 1, (p319)

    Change:

    guard let db = FMDatabase(path: booksFile.path) else {
                  print("unable to create database")
    return nil }

    to:

    let db = FMDatabase(path: booksFile.path)

    Chapter 11, 11.2.5 "Updating and Deleting Managed Objects" Step 2 code block (p333)

    Replace:

    UITableViewCellEditingStyle

    With:

    UITableViewCell.EditingStyle

    Chapter 12, 12.3.2 "Escaping closures" (p349)

    Remove:

    "used as an argument when calling another function, "

    Chapter 12, 12.3.2 "Adding a book record to CloudKit" point 7 code block (p350)

    Replace:

    activityIndicatorStyle

    With:

    style

    Chapter 12, Listing 12.2 "Add notification info to subscription" code block (p364)

    Replace:

    CKNotificationInfo()

    With:

    CKSubscription.NotificationInfo()

    Chapter 12, 12.3.8 "Request a database subscription" point 1 code block (p365)

    Replace:

    CKNotificationInfo()

    With:

    CKSubscription.NotificationInfo()

    Chapter 13, 13.1.2 "Adding app icons" (p377)

    Remove the following:

    (although this icon doesn't need to be included in your app bundle)

    Chapter 13, 13.3.7 "Creating a star rated view" point 6 code block (p388)

    Replace:

    guard let starIndex = stars.index(of: star) else {return}

    With:

    guard let starIndex = stars.firstIndex(of: star) else {return}

    Chapter 13, 13.5.1 "Taking photos..." point 5 code block (p395)

    Replace:

    didFinishPickingMediaWithInfo info: [String: Any]) {

    With:

    didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {

    Chapter 13, 13.5.1 "Taking photos..." point 6 (p395)

    Replace:

    "and stored against the

    UIImagePickerControllerOriginalImage
    key."

    With:

    "and stored against the

    UIImagePickerController.InfoKey.originalImage
    key."

    Chapter 13, 13.5.1 "Taking photos..." point 7 code block (p395)

    Replace:

    if let image = info[UIImagePickerControllerOriginalImage]

    With:

    if let image = info[UIImagePickerController.InfoKey.originalImage]

    Chapter 13, 13.5 "Detecting a barcode" Note, (p402)

    Change:

    "...you'd use the devices method, which you could use to return an array of all available cameras. You could then use the position property on the AVCaptureDevice objects to find the front camera. "

    to:

    "...you'll need to instantiate an AVCaptureDevice.DiscoverySession object, passing in the front position property to find the front camera. You would then get an array of relevant devices from the devices property. "

    Chapter 14, 14.2 Step 8, (p413)

    Code block, change from:

        }
    } else {
        // Deal with no error, no book!
    }

    to:

        } else {
            // Deal with no error, no book!
        }
    }

    Add new sentence following code block:

    "As you have done previously, you'll need to surround this try in a do-catch statement."

    Chapter 14, 14.5 "Setting up the URL request" Step 3, (417)

    networkServiceType should be a dot point, rather than step, 4.

    Chapter 14, 14.10.2 Step 3, (p430)

    Code block, change from:

    let dataAsJSON = JSON(data: data)

    to:

    let dataAsJSON = try JSON(data: data)

    Add new sentence following code block:

    "As you have done previously, you'll need to surround this try in a do-catch statement."

    Chapter 14, 14.10.2 Step 4, (p430)

    Code block, before:

    ↳ "title"].string,

    please add open square bracket:

    ↳ ["title"].string,

    Also before :

    ↳ "authors"].arrayObject as? [String] {

    please add open square bracket:

    ↳ ["authors"].arrayObject as? [String] {

    Chapter 14, 14.11 Step 1, (p432)

    Code block :

    let thumbnailURL = volumeInfo["imageLinks"]?["thumbnail"].string {

    Should be: (remove the question mark)

    let thumbnailURL = dataAsJSON["items"][0]["volumeInfo"]["imageLinks"]["thumbnail"].string {

    Chapter 15, 15.1 fourth bullet point, (p440)

    The following sentence:

    "I've also added properties for these colors in the Book class."

    Should read:

    "I've also added properties for these colors in the Book struct."

    Chapter 15, 15.3 (p445)

    The following sentence:

    "Look for main at line 29 of figure 15.3."

    Should read:

    "Look for main at line 24 of figure 15.3."

    Also, the following sentence:

    "You'll find this in the call stack too, at line 28."

    Should read:

    "You'll find this in the call stack too, at line 23."

    Chapter 15, 15.4.1, point 2 (p449)

    Add an instruction between points 2 and 3:

    "Adopt the CustomStringConvertible protocol:"

    struct Book: Codable, CustomStringConvertible {

    Output :

    Saving book: Book(title: "Five on Brexit Island", author: "Enid Blyton", rating: 3.0, isbn: " 9781786488077", notes: "", image: Optional(, {128, 202}), backgroundColor: UIExtendedGrayColorSpace 1 1, primaryColor: UIExtendedGrayColorSpace 0 1, detailColor: UIExtendedGrayColorSpace 0 1)

    Should be:

    Saving book: Book(title: "Five on Brexit Island", author: "Enid Blyton", rating: 3.0, isbn: " 9781786488077", notes: "", image: nil, backgroundColor: UIExtendedGrayColorSpace 1 1, primaryColor: UIExtendedGrayColorSpace 0 1, detailColor: UIExtendedGrayColorSpace 0 1)

    Chapter 15, 15.4.1 point 3, (p449)

    The following sentence:

    "Add a description property to the Book class..."

    should read:

    "Add a description property to the Book struct..."

    Code block:

    override var description: String {

    should read:

    var description: String {

    Chapter 15, 15.5 quote, (p459)

    The following sentence:

    "I've also added properties for these colors in the Book class..."

    should read:

    ,

    "I've also added properties for these colors in the Book struct..."

    Chapter 15, 15.7.1 Setting up your text class, (p471)

    The following code block:

    booksManager = BooksManager() 
                     booksManager.addBook(bookDaVinci)

    Requires an extra line:

    booksManager = BooksManager() 
                     booksManager.resetBooks()
                     booksManager.addBook(bookDaVinci)

    Add after code block (and before note):

    "2 Notice that we've reset the books in the array with a resetBooks method. We'll need to implement this method in the BooksManager class:"

    func resetBooks() {
                         books = []
                     }

    We will then need to renumber the following point:

    "3 Add a testable import at the top..."

    Chapter 15, 15.7.1 "Adding tests to your test class" Step 5, (p473)

    Change the following:

    "You may have noticed your test class has a setup method.

    To have a capital 'u' in setUp:

    "You may have noticed your test class has a setUp method.

    Also, code block :

    XCTAssert(booksManager.getBook(at: 0) == bookDaVinci)
                     XCTAssert(booksManager.getBook(at: 1) == bookOdyssey)
                     XCTAssert(booksManager.getBook(at: 2) == bookGulliver)

    Should be:

    XCTAssertEqual(booksManager.getBook(at: 0), bookDaVinci)
                     XCTAssertEqual(booksManager.getBook(at: 1), bookOdyssey)
                     XCTAssertEqual(booksManager.getBook(at: 2), bookGulliver)

    Chapter 16 "Distributing your App" (p481)

    In June 2018, Apple changed the name of "iTunes Connect" to "App Store Connect." To remain current, all references to iTunes Connect in this chapter should be updated to "App Store Connect."

    Chapter 17, 17.1 "Further learning" (p513)

    Apple has consolidated separate pages of documentation into one. Please remove lines: "Apple API reference documentation" and "iOS Frameworks" and rename "Guides and sample code" to "Guides, sample code and API documentation."

    Chapter 17, 17.1 "Further learning" (p513)

    Please replace URL for "Yahoo's FLurry." It should be "http://www.flurry.com"