Skip to content

Instantly share code, notes, and snippets.

@0thernet
Last active August 29, 2015 14:02
Show Gist options
  • Save 0thernet/4f33182ae11fa3033355 to your computer and use it in GitHub Desktop.
Save 0thernet/4f33182ae11fa3033355 to your computer and use it in GitHub Desktop.

WWDC 2014 Brain Lanier

Optionals

  • Cleaner alternative to using sentinels (NULL, NSNotFound, etc.) to represent invalid values
  • optionals are initialized to nil by default
    • var optionalNumber: Int?
  • nil is a sentinel value that works with any type
  • value is wrapped in optional by setter
    • optionalNumber = 6
  • Non-optional types can't be nil
    • var myString: String = nil
  • enumerate returns (index, value) for each element in an array

Unwrapping optionals with Optional Binding

let index: Int? = findIndexOfString("Madison", neighbors)
// if index is not nil, its value will be assigned to indexValue
if let value = funcReturningOptional("foo") { 
	// do something
}

Optional Chaining

  • addressNumber = paul.residence?.address?.buildingNumber?.toInt()
  • c.f. passing messages to nil in obj-c

Optional Chaining + Optional Binding

if let value = paul.residence?.address?.toInt() {

}

Optionals under the hood

enun Optional<T> {
	case None
	case Some(T)
}

Memory management

ARC

  • Swift uses ARC
  • Reference cycles
    • use weak references
    • weak var Person
  • Weak references are optionals
    • Binding a weak reference with let produces a strong reference
    • Testing a weak reference doesn't produce a strong reference
    • Chaining doesn't preserve a strong reference between method invocations
  • Unowned refs can be used just like strong refs
  • Use strong references from owners to the objects they own
  • Use weak refs among objects with independent lifetimes
  • Use unowned references from owned objects with the same lifetime
    • great for back references from dependent objects back up to their owners

Initialization

  • Every value must be initialized before it is used
  • Swift doesn't default initialize variables, constants, or properties
    • optionals are the one exception
  • use of an uninitialized variable is a compiler error

Initializers

  • handle responsibility of fully initializing an instance

Structs

struct Color {
	let red = 1.0, green = 1.0, blue = 1.0
	init(grayScale: Double) {
		red = grayScale
		green = grayScale
		blue = grayScale
	}
}
  • member-wise initializer, default initializer

Classes

  • call superclass's initializer after setting own properties
    • ensures memory safety
    • superclass may modify properties at the end of its initializer
    • subclass must set its own properties before letting the superclass

Convenience initializers

  • Designated initializers only delegate up
  • Convenience initializers only delegate across
convenience init() {
	self.init(color: Color(gray: 0.4))
}

Initializer inheritance

  • not inherited by default
  • if all properties are given default values and there's no initializer, all superclass initializers are inherited

Lazy properties

@lazy var multiplayerManager = MultiplayerManager()

  • Only initialized once when first accessed

Deinitialization

deinit {
	closeFile(fileDescriptor)
}

Closures

clients.sort){(a: String, b: String) -> Bool in
	return a < b
}

Type Inference

  • sort knows that it takes two strings and returns a bool
clients.sort {a, b in
	return a < b
}

Implicit return

  • single expression closure implicitly returns
clients.sort({a, b in a < b})

Implicit parameters

clients.sort({$1 < $2})

Functional programming

words.filter {$0.hasSuffix("gry")} .map {$0.uppercaseString }
  • functions can be used wherever closures are used

Closures are ARC objects

Functions are ARC objects

Ownership of Captures

  • storing a closure property that references self creates a reference cycle. Use unowned
unowned let uSelf = self
onChange = { temp in
	uSelf.currentTemp = temp
}
  • Even better: Specify how closure should capture its local state
onChange = { [unowned self] temp in
	self.currentTemp = temp
}

Pattern matching

enum Status {
	case OnTime
	case Delayed(Int)
}
switch trainStatus {
	case .OnTime:
		println("on time")
	case .Delayed(let minutes)
	case .Delayed(2)
	case .Delayed(2..10):
	case .Delayed(_)
}

Patterns compose

switch vacationStatus {
	case .Traveling(.OnTime):
	case .Traveling(.Delayed(1..15)):
}

Type Patterns

func tuneUp(car: Car) {
	switch car {
		case let formulaOne as FormulaOne:
			formulaOne.enterPit()
		//...
}

Tuple Patterns

let color = (1.0, 1.0, 1.0, 1.0)
switch color {
	case (0.0, 0.5..1.0, let blue, _):
		//
	case let (r, g, b, 1.0) where r == g && g == b:
		//
}

Validating a property list

func stateFromPlist(list: Dictionary<String, AnyObject>) -> State? {
	switch (list["name"], list["population], list["abbr"]) {
		case (.Some(let name as String),
			   .Some(let pop as Int),
			   .Some(let abbr as String))
		where abbr. length == 2:
			return State(name: name, population: pop, abbr: abbr)
		default:
			return nil
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment