Type safe

Don’t need to check hundred times, don’t need NSParameterAssert in most cases.

if (username.length > 0) {
[[MWEDaemon daemon].currentInterfaceController didReceivedYoCount:count fromUsername:username type:type];
}
func didReceivedYoCount(count: UInt, fromUsername username: String, type: Int) {
presentControllerWithName("MWEYoController", context: ["username": username, "count": count, "type": type])
}
- (void)didReceivedYoCount:(NSUInteger)count fromUsername:(NSString *)username type:(int)type {
// already check nil parameters when call
if (username == nil) {
return;
}
NSParameterAssert(username);
[self presentControllerWithName:@"MWEYoController" context:@{@"username": username, @"count": @(count), @"type": @(type)}];
}

Generics

struct IntStack {
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
struct Stack<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}

Enum

enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}

var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")

switch productBarcode {
case let .UPCA(numberSystem, manufacturer, product, check):
print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .QRCode(productCode):
print("QR code: \(productCode).")
}
// prints "QR code: ABCDEFGHIJKLMNOP."

There is another a very popular use case about check result, here is a example in Alamofire/Result.swift

Default Prameter Values

Function definition will be much more graceful.

func someFunction(parameterWithDefault: Int = 22) {
// function body goes here
}

// call
someFunction()
someFunction(1)

Functions with Multiple Return Values (Tuples)

func minMax(array: [Int]) -> (min: Int, max: Int)? {
// function body goes here
}

Function Types as Parameter Types

func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)

Closure Expressions

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

All of the codes below do the same thing:

func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = names.sort(backwards)
reversed = names.sort({ (s1: String, s2: String) -> Bool in
return s1 > s2
})
reversed = names.sort({ s1, s2 in return s1 > s2 })
reversed = names.sort({ s1, s2 in s1 > s2 })
reversed = names.sort({ $0 > $1 })
reversed = names.sort(>)

guard

Before:

func somethingDidChanged(notification: NSNotification) {
if let contact = notification.userInfo?["contact"] as? MWEContact {
if let message = notification.userInfo?["message"] as? MWEMessage {
// do something
}
}
}

After:

func somethingDidChanged(notification: NSNotification) {
guard let contact = notification.userInfo?["contact"] as? MWEContact else {
return
}

guard let message = notification.userInfo?["contact"] as? MWEMessage else {
return
}

// do something
}

Could be better:

func somethingDidChanged(notification: NSNotification) {
guard let contact = notification.userInfo?["contact"] as? MWEContact,
message = notification.userInfo?["message"] as? MWEMessage else {
return
}

// do something
}

defer

func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// Work with the file.
}
// close(file) is called here, at the end of the scope.
}
}

Protocol Extensions

  • WWDC 2015 - Session 408 - Protocol-Oriented 
 Programming in Swift
class PresentErrorViewController: UIViewController {
var errorViewIsShowing: Bool = false
func presentError(message: String = Error!", withArrow shouldShowArrow: Bool = false, backgroundColor: UIColor = ColorSalmon, withSize size: CGSize = CGSizeZero, canDismissByTappingAnywhere canDismiss: Bool = true) {
//do complicated, fragile logic
}
}

//Over 100 classes inherited from this class, by the way.
class EveryViewControllerInApp: PresentErrorViewController {}

protocol ErrorPopoverRenderer {
func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool)
}

extension UIViewController: ErrorPopoverRenderer { //Make all the UIViewControllers that conform to ErrorPopoverRenderer have a default implementation of presentError
func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool) {
//add default implementation of present error view
}
}

class KrakenViewController: UIViewController, ErrorPopoverRenderer { //Drop the God class and make KrakenViewController conform to the new ErrorPopoverRenderer Protocol.
func methodThatHasAnError() {
//…
//Throw error because the Kraken sucks at eating Humans today.
presentError(/*blah blah blah much parameters*/)
}
}

the Swift runtime calls the presentError() through static dispatch instead of through dynamic dispatch.

Some code snippets

let b = a ?? "default"
if #available(iOS 9, OSX 10.10, *) {
// Use iOS9 APIs on iOS, and use OS X v10.10 APIs on OS X
} else {
// Fall back to earlier iOS and OS X APIs
}
prepareSomething() // NOT use 'self.' unless it's necessary
// self.prepareSomething() // don't do this
contact.getHeadImageThumbnail { [weak self] (object, error) -> Void in
// blabla
self.updateUI()
}

Tips

Use Playground to test something when coding.

Summay