2017-03-16: Updated for Swift 3.0

I’ve been doing iOS and Mac OS programming in Swift for a while and I noticed some “pitfalls”. They are some syntax details that may cause compiler errors and leave you wonder, “why is that”. I believe that all the “pitfalls” here are included in the Swift official documentation and tutorials already. But I think it would help myself and other people if I put them all together here in one place.


1. Naming of methods

The following code won’t work:

class TestClass {
  class func print(_ string: String) {
    print("Test: \(string)")
    // The above line will call itself i.e. `TestClass.print(_:)`
    // instead of `print(_:​separator:​terminator:​)` in Swift Standard Library
    // leading to an infinite cycle
  }
  
  init() {
    TestClass.print("init")
  }
}

Fix:

  class func print(_ string: String) {
    Swift.print("Test: \(string)")
  }


2. Exposing method to Objective-C

In Swift 3.0, the following code won’t compile:

// Does not work
class TestClass { // Not a subclass of `NSObject`
  func setUp() {
    button.addTarget(
      self,
      action: #selector(buttonTapped(_:)),
      for: .touchUpInside)
  }

  private func buttonTapped(sender: Any) { // Private
  }
}

Error message would be Argument of '#selector' refers to instance method 'buttonTapped' that is not exposed to Objective-C'


Fix by adding @objc to the method:

class TestClass {
  @objc private func buttonTapped(sender: Any) {
  }
}

Thanks to reader Jon Showing for their input.


3. Single line expression in closures: Implicit ‘return’

func moveViewsToCenter() {
}

func makeViewsVisible() -> Bool {
}

func performAnimation() {
  // Works!
  let animationsA = { () -> Void in
    self.moveViewsToCenter()
  }
          
  // Swift 2.3: Won't compile
  // Swift 3.0: Warning with message
  //   "Result of call to 'makeViewsVisible()' is unused"
  let animationsB = { () -> Void in
    self.makeViewsVisible() 
  }

  // Works!
  let animationsC = { () -> Bool in
    self.makeViewsVisible()
    // This is equivalent to writing
    // `return self.makeViewsVisible()`
  }
}


Fix by either adding @discardableResult to the method,

@discardableResult func makeViewsVisible() -> Bool {
}

or

  let animationsB = { () -> Void in
    let _ = self.makeViewsVisible()
  }


4. Closures that take no parameters and return Void

You COULD write: () -> () OR () -> Void

// Valid!
let closure = { () -> () in
}

// Valid!
let closure = { () -> Void in
}

BUT NOT Void -> ()

// ERROR! Invalid!
let invalidClosure = { /* ERROR! */ Void -> () in
}


But, the easiest is probably:

// Valid!
let closure = {
  // Your code
}