Categories
Uncategorized

Why your Swift apps broke in Xcode 6 beta 7 and the GM versions, and how to fix them

xcode beta 7 broke everything

If you had Swift projects that worked perfectly fine under Xcode 6 beta 6, you might find that they no longer work under beta 7 or the GM versions. This article will show you how to fix them, and why they broke.

For example, the FlappySwift game on GitHub — “Flappy Bird”, implemented in Swift — worked fine in Xcode 6 beta 6 and earlier, but is rife with errors in the present version of Xcode:

flappyswift code screencap

Click the screen capture to see it at full size.

Most of the errors are of the form “[SomeClass]? does not have a member named [SomeMember]”. The fix is simple — use optional chaining to fix the problem. For example, code like this:

pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize: pipeDown.size)
pipeDown.physicsBody.dynamic = false
pipeDown.physicsBody.categoryBitMask = pipeCategory
pipeDown.physicsBody.contactTestBitMask = birdCategory
pipePair.addChild(pipeDown)

should be changed to:

pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize: pipeDown.size)
pipeDown.physicsBody?.dynamic = false
pipeDown.physicsBody?.categoryBitMask = pipeCategory
pipeDown.physicsBody?.contactTestBitMask = birdCategory
pipePair.addChild(pipeDown)

Note the addition of a ? — the optional chaining operator — to physicsBody when accessing one of its members. Make changes like this to FlappySwift’s code (it won’t take longer than a couple of minutes), and it’ll work again.

What happened?

It’s not as if Apple didn’t tell you what happened. It’s all spelled out in the Xcode 6 beta 7’s release notes:

A large number of Foundation, UIKit, CoreData, SceneKit, SpriteKit, Metal APIs have been audited for optional conformance, removing a significant number of implicitly unwrapped optionals from their interfaces. This clarifies the nullability of their properties, arguments and return values of their methods. This is an ongoing effort that started shipping in beta 5. These changes replace T! with either T? or T depending on whether the value can be null or not null, respectively.

It’s perfectly understandable if you read that and this was your reaction:

beavis and butt-head wtf

We’ll translate this into plain language, but first, let’s do a quick review of non-optional, optional, and implicitly unwrapped optional variables.

Non-optionals, optionals, and implicitly unwrapped optionals: a quick review

optional 1 In Swift, a variable whose type that doesn’t have any punctuation is guaranteed to contain a value of that type. For example, a variable of type String is guaranteed to contain a string value, even if that string is a zero-length string (“”). It will never be nil (nil means that the variable doesn’t contain a value), and you can start performing string operations on its value immediately.

Of course, there are times when you want a variable that might not contain a value at the moment, to indicate that you haven’t yet recorded a value or to denote that there’s no connection to another object. That’s what optionals are for: optional 2 Variables in Swift whose type ends with a question mark — ? — are called optionals, and they’ll either contain a value of that type or nil (which means that it contains no value). You’ll need to perform a check to see if contains a value or is empty first, and you’ll need to unwrap it before you can use its value.

For example, a variable of type String? will contain either a string value or nil. An often-cited example for showing optionals in action starts with a Dictionary with String keys and values, like the one below:

let airports = [
  "YYZ" : "Toronto Pearson",
  "YUL" : "Montreal Pierre Elliott Trudeau",
  "TPA" : "Tampa",
  "SFO" : "San Francisco",
  "ORD" : "Chicago O'Hare"
]

This dictionary lets you look up the name of an airport given its three-letter code like so:

let airportName = airports[airportCode]

You might think that the type of airports[airportCode] is String, but it’s not — it’s String?. That’s because the value of airports[airportCode] will be either:

  • a String value, if the value for airportCode corresponds to one of the dictionary’s keys: YYZ, YUL, TPA, SFO, or ORD, or
  • nil, if the value for airportCode isn’t one of the dictionary’s keys, such as LAX.

With optionals, you’ll write code that first checks to see whether or not they contain a value, and if they do, unwrap them with the ! operator. Here’s an example that continues with our dictionary:

if airports[airportCode] != nil {
  // We CAN'T do string operations on airports[airportCode] since
  // not a string, but an optional. We have to unwrap it first
  // with the ! operator.
  let airportName = airports[airportCode]!

  // We CAN do string operations with airportName, since it IS a string.
  let phrase = "The airport's name is: " + airportName
  println(phrase)
}
else {
  println("Airport name unknown.")
}

This sort of check is going to happen quite often, so Swift’s designers added the “iflet” shorthand to save reduce the amount of code you have to write:

// If airports[airportCode] isn't nil, assign its value to airportName,
// which is a string.
if let airportName = airports[airportCode] {
  let phrase = "The airport's name is: " + airportName
  println(phrase)
}
else {
  println("Airport name unknown.")
}

You can also unwrap an optional by assigning its value to an implicitly unwrapped optional:

optional 3 Variables in Swift whose type ends with an exclamation mark — ! — are called implicitly unwrapped optionals, and they’re optionals you don’t have to unwrap in order to access the value they hold. When you want to work with the contents of an optional, you can either use the ! operator to unwrap it, or you can assign its value to an implicitly unwrapped optional, like so:

var tampaAirport: String! = airports["TPA"]

in which case tampaAirport is a String! variable. It’s still an optional, but you can use it as if it were a regular string variable. It’s still an optional, and it can be nil. There’s a coding convention that promises that by the time you need to access an implicitly unwrapped optional’s contents, it’ll hold a value.

This “it may have been nil at one point, but I promise it’ll contain a value by the time you use it” property of implicitly unwrapped optionals make them useful for instance variables whose values can’t be set when they’re declared. For example, suppose we need variables to store the width and height of the screen — values that we can’t know in advance:

class ViewController: UIViewController {

  // We want instance variables to hold the screen's width and height,
  // but we won't know what values to set them to until the app is running.
  // So we'll declare them as implicitly unwrapped optionals.
  var screenWidth: CGFloat!
  var screenHeight: CGFloat!
  
  override func viewDidLoad() {
    super.viewDidLoad()

    // NOW we can fill those screen width and height variables!
    let screenSize = UIScreen.mainScreen().bounds
    screenWidth = screenSize.width
    screenHeight = screenSize.height
  }

  // (the rest of the class goes here)

That’s the review. Now let’s look at why your code broke.

Why your code broke after Xcode 6 beta 7 and later

This long answer on Stack Overflow explains implicitly unwrapped optionals exist. Long story short, they’re a practical compromise that allows Swift, which purposely doesn’t have null pointers, to work with iOS’ existing APIs, which were written with Objective-C, its pointers, and its conventions in mind.

There were a number of iOS APIs that were returning values as implicitly unwrapped optionals because they’re as close as you get to pointers in Swift: they can either hold a reference or nil, and you can access them directly without unwrapping them. Over time, Apple have been updating these APIs so that they followed the rules for optionals — if they might return nil, return the value as an optional, otherwise, return the value as a non-optional. Hence the term “optional conformance”. With the release of Xcode 6 beta 7, and after that, Xcode 6 GM, most of the APIs now conform to the rules for optionals. If an API call returns a value that could be nil, it’s no longer returned as an implicitly unwrapped optional, but as an optional. Here’s a snippet of code from my “Simple Shoot ‘Em Up” game that worked in Xcode 6 versions prior to beta 7. It assigns physics bodies to missile sprites:

// Give the missile sprite a physics body.
// This won't work on Xcode 6 beta 7 or GM!
missile.physicsBody = SKPhysicsBody(circleOfRadius: missile.size.width / 2)
missile.physicsBody.dynamic = true
missile.physicsBody.categoryBitMask = missileCategory
missile.physicsBody.contactTestBitMask  = alienCategory
missile.physicsBody.collisionBitMask = 0
missile.physicsBody.usesPreciseCollisionDetection = true

It used to work when the SKPhysicsBody(circleOfRadius) initializer returned an object of type SKPhysicsBody!, which granted access to its properties. As of Xcode 6 beta 7 and later, SKPhysicsBody(circleOfRadius) returns an object of type SKPhysicsBody?. You need to unwrap it to get at its properties, which you can do through optional chaining, as shown below:

// Give the missile sprite a physics body.
// This won't work on Xcode 6 beta 7 or GM!
missile.physicsBody = SKPhysicsBody(circleOfRadius: missile.size.width / 2)
missile.physicsBody?.dynamic = true
missile.physicsBody?.categoryBitMask = missileCategory
missile.physicsBody?.contactTestBitMask  = alienCategory
missile.physicsBody?.collisionBitMask = 0
missile.physicsBody?.usesPreciseCollisionDetection = true

My suggested general guideline is that if you’re dealing with an API call or property that returns a pointer, you’re dealing with an optional that you’ll need to unwrap. You can always check the type of an entity in Xcode by putting your cursor over it and alt-clicking:

returning a pointer

2 replies on “Why your Swift apps broke in Xcode 6 beta 7 and the GM versions, and how to fix them”

Comments are closed.