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