Skip to content

Instantly share code, notes, and snippets.

@jamesyang124
Last active August 29, 2015 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesyang124/4fc6409f8d9489ba03d0 to your computer and use it in GitHub Desktop.
Save jamesyang124/4fc6409f8d9489ba03d0 to your computer and use it in GitHub Desktop.
Side notes from CS193P course in Stanford University.

Lecture 1

  1. Constraint and auto layout.
  • Auto Layout Concepts
  • The attributes leading and trailing are the same as left and right for left-to-right languages such as English, but in a right-to-left environment such as Hebrew or Arabic, leading and trailing are the same as right and left.
  • Constraints are cumulative, and do not override each other. Setting a second width constraint for a view does not remove or alter the first width constraint.
  1. @IBOutlet weak var prpoerty.
  1. ARC

Lecture 2

  1. Function types
  2. Closure & Type inferring
  3. SPL = Swift Programming Language book.

###Reading - SPL: The Basics

  • Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers.

  • If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context.

  • To convert one specific number type to another, you initialize a new number of the desired type with the existing value.

    // UInt16(s) -> convert s to UInt16 integer. 
    var ui8: UInt8 = 2_000
    var ui16: UInt16 = 1
    var combine = UInt16(ui8) + ui16
  • Type Alias

    typealias AudioSample = UInt16
    var aliasMin = AudioSample.min
  • Swift’s type safety prevents non-Boolean values from being substituted for Bool.

  • Tuples group multiple values into a single compound value.

    let HttpError = (404, "HttpError")
    let (status, description) = HttpError 
    println("Status Code \(Status)")
    println("Description is \(Description)")
  • You use Optionals in situations where a value may be absent. There exist a value or could be nil when its optional.

  • nil cannot be used with nonoptional constants and variables. If the value of a variable or constant may be absent, then should declare it as optional type.

  • An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all.

    // Declare optional type without default value, then it is automatically set to nil.
    var surveyAnswer: String?
  • Optional binding can be used with if and while statements to check for a value inside an optional.

    if let constantName = someOptional, varName = anotherOptional {
      statements  
    }
    
    if let actualNumber = possibleNumber.toInt() {
      println("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
    } else {
      println("\'\(possibleNumber)\' could not be converted to an integer")
    }
  • Implicitly Unwrap optionals Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. It is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time.

    let possibleString: String? = "An optional string."
    let forcedString: String = possibleString! // requires an exclamation mark
    
    let assumedString: String! = "An implicitly unwrapped optional string."
    let implicitString: String = assumedString // no need for an exclamation mark
  • You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement.

    let assumedString: String! = "An implicitly unwrapped optional string."
    if let definiteString = assumedString {
      println(definiteString)
    }
  • Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution.

    let age = -3
    assert(age >= 0, "A person's age cannot be less than zero")
    // this causes the assertion to trigger, because age is not >= 0

###Reading - SPL: Basic Operators

  • Prefix ++ or postfix ++.

    var a = 0
    let b = ++a
    // a and b are now both equal to 1
    let c = a++
    // a is now equal to 2, but c has been set to the pre-increment value of 1
  • Minus and Plus operator.

    let three = 3
    let minusThree = -three       // minusThree equals -3
    let plusThree = +minusThree   // Thoguh have plus operator, minusThree equals -3
  • The compound assignment operators(+=) do not return a value. You cannot write let b = a += 2

  • The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type.

    (a ?? b) == (a != nil ? a! : b)
  • Range operators

    (a...b)  // include a to b, not the same as Ruby's syntax
    (a..<b)  // include a but not b. Half-open range operators.

###Reading - SPL: Strings and Characters

  • Create an empty String value as the starting point for building a longer string by assigning to "" or String().

    var emptyString = ""               // empty string literal
    var anotherEmptyString = String()  // initializer syntax
    // these two strings are both empty, and are equivalent to each other
  • String Mutability

    var variableString = "Horse"
    variableString += " and carriage"
    // variableString is now "Horse and carriage"
    
    let constantString = "Highlander"
    constantString += " and another Highlander"
    // this reports a compile-time error - a constant string cannot be modified
  • String are Value types. String variable is passing to an method's argument by copying by value.

  • Claim a Character type by explicitly Character annotation.

    let exclamationMark: Character = "!"
    let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
    let catString = String(catCharacters)
    println(catString)
    // prints "Cat!🐱"
  • You can append a Character value to a String variable with the String type’s append() method.

    let exclamationMark: Character = "!"
    welcome.append(exclamationMark)
    // welcome now equals "hello there!"
  • Special Characters in String Literals

    let wiseWords = "\"Imagination is more" + 
    	" important than knowledge\" - Einstein"
    // "Imagination is more important than knowledge" - Einstein
    let dollarSign = "\u{24}"        // $,  Unicode scalar U+0024
    let blackHeart = "\u{2665}"      // ♥,  Unicode scalar U+2665
    let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496
  • Extended Grapheme Clusters: Every instance of Swift’s Character type represents a single extended grapheme cluster. An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.

    let eAcute: Character = "\u{E9}"                  // é
    let combinedEAcute: Character = "\u{65}\u{301}"   // e followed by ́
    // eAcute is é, combinedEAcute is é
  • Counting Characters: if you initialize a new string with the four-character word cafe, and then append a COMBINING ACUTE ACCENT (U+0301) to the end of the string, the resulting string will still have a character count of 4, with a fourth character of é, not e.

    let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
    println("unusualMenagerie has \(count(unusualMenagerie)) characters")
    // prints "unusualMenagerie has 40 characters"
  • Use the startIndex property to access the position of the first Character of a String, and the endIndex property to access the posision of the last. If the String is empty, startIndex and endIndex are equal.

    let greeting = "Guten Tag"
    println(greeting.startIndex)
    // 0
    println(greeting.endIndex)
    // 9
    
    // Use the global function indicies(_:) to create a Range 
    // of all of the indexes used to access individual characters in a string.
    for (index in indices(greeting)) {
      print("\(greeting[index]) ")
    }
    println("\n")
    // prints "G u t e n   T a g"
  • insert(_:atIndex:), removeAtIndex(_:), splice(_:atIndex:), and removeRange(_:).

    var welcome = "hello"
    welcome.insert("!", atIndex: welcome.endIndex)
    
    // To insert another string at a specified index, use splice
    welcome.splice(" there", atIndex: welcome.endIndex.predecessor())
    // welcome now equals "hello there!"
    
    // To remove a character from a string at a specified index, use removeAtIndex
    welcome.removeAtIndex(welcome.endIndex.predecessor())
    // welcome now equals "hello there"
    
    //To remove a substring at a specified range, use the removeRange
    let range = advance(welcome.endIndex, -6)..<welcome.endIndex
    welcome.removeRange(range)
    // welcome now equals "hello"
  • Two String values (or two Character values) are considered equal if their extended grapheme clusters are canonically equivalent.

    // "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE
    let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
    
    // "Voulez-vous un café?" using 
    // LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
    let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
    
    if eAcuteQuestion == combinedEAcuteQuestion {
      println("These two strings are considered equal")
    }
    // prints "These two strings are considered equal"
  • hasPrefix(_), hasSuffix(_) accept a String argument. The hasPrefix(_:) and hasSuffix(_:) methods perform a character-by-character canonical equivalence comparison between the extended grapheme clusters in each string.

  • utf8 or utf16.

    for codeUnit in dogString.utf8 {
      print("\(codeUnit) ")
    }
    print("\n")
    // 68 111 103 226 128 188 240 159 144 182  
  • You can access a Unicode scalar representation of a String value by iterating over its unicodeScalars property. This property is of type UnicodeScalarView, which is a collection of values of type UnicodeScalar.

  • Each UnicodeScalar has a value property that returns the scalar’s 21-bit value, represented within a UInt32 value.

    for scalar in dogString.unicodeScalars {
      print("\(scalar.value) ")
    }
    print("\n")
    // 68 111 103 8252 128054
    // 8252 to hex decimal is 203c 
    // which is U+203c for the DOUBLE EXCLAMATION MARK character
    
    for scalar in dogString.unicodeScalars {
      print("\(scalar) ")
    }
    // D o g ‼ 🐶

###Reading - SPL: Collection Types

  • Arrays

    var someInts = [Int]()
    
    someInts.append(3)
    // someInts now contains 1 value of type Int
    someInts = []
    // someInts is now an empty array, but is still of type [Int]
    
    // another initializer of array
    var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
    // threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
    
    // Array Literal
    var ary: [Int] = [2,3,4,5]
    // declare by Swift’s type inference
    var arys = [2,3,4,5,5]
  • You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing.

    var shoppingList = ["s", "h", "o", "p", "p", "i", "n", "g", "L"]
    shoppingList[4...6] = ["Bananas", "Apples"] 
    // shoppingList now contains 6 items
  • You can’t use subscript syntax to append a new item to the end of an array. But can use additional assignment operator.

    shoppingList += ["Baking Powder"]
    // shoppingList now contains 4 items
    shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
    // shoppingList now contains 7 items
    
    var firstItem = shoppingList[0]
    // use subscript syntax to retrieve firstItem is equal to "Eggs"
  • use insert(_:atIndex:) method to insert value to specific index.

    shoppingList.insert("Maple Syrup", atIndex: 0)
  • A set stores distinct values of the same type in a collection with no defined ordering. The type of a Swift set is written as Set<SomeType>, where SomeType is the type that the set is allowed to store. Unlike arrays, sets do not have an equivalent shorthand form.

    var letters = Set<Character>()
    println("letters is of type Set<Character> with \(letters.count) items.")
    // prints "letters is of type Set<Character> with 0 items."
    
    letters.insert("a")
    // letters now contains 1 value of type Character
    letters = []
    // letters is now an empty set, but is still of type Set<Character>
  • Set use inset(_:), remove(_:), contains(_:) method to add, remove, check elements.

  • Iterate set cannot gurantee its iteration order, but can pass set to sorted method then iterate out.

    for genre in sorted(favoriteGenres) {
      println("\(genre)")
    }
    // Classical
    // Hip hop
    // Jazz
  • Use union(_:), subtract(_:), intersect(_:), and exclusiveOr(_:) to operate set relations.

  • Use isSubsetOf(_:), ==, isSupersetOf(_:), isStrictSubsetOf(_:), or isStrictSupersetOf(_:), and isDisjointWith(_:) to compare sets.

  • A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself. A hash value is an Int value that is the same for all objects that compare equal, such that if a == b, it follows that a.hashValue == b.hashValue.

  • Dictionary

    var namesOfIntegers = [Int: String]()
    // namesOfIntegers is an empty [Int: String] dictionary
    
    namesOfIntegers[16] = "sixteen"
    // namesOfIntegers now contains 1 key-value pair
    namesOfIntegers = [:]
    // namesOfIntegers is once again an empty dictionary of type [Int: String]
    
    // Dictionary literals
    var airports: [String: String] = ["YYZ": "Toronto Pearson",
    		 "DUB": "Dublin"]
  • As an alternative to subscripting, use a dictionary’s updateValue(_:forKey:) method to set or update the value for a particular key.

  • The updateValue(_:forKey:) method returns an optional value of the dictionary’s value type. This optional value contains the old value for that key if one existed before the update, or nil if no value existed.

    var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
    
    if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
      println("The old value for DUB was \(oldValue).")
    }
    // prints "The old value for DUB was Dublin."
  • You can also use subscript syntax to retrieve a value from the dictionary for a particular key. If the key does not exist, then return nil. Also, we can remove a key-value pair by assign nil value to a key, or removeValueForKey(_:).

    airports["APL"] = "Apple International"
    // "Apple International" is not the real airport for APL,
    // so delete it
    airports["APL"] = nil
    // APL has now been removed from the dictionary
  • Each item in the dictionary is returned as a (key, value) tuple.

  • Swift’s Dictionary type does not have a defined ordering. To iterate over the keys or values of a dictionary in a specific order, use the global sorted function on its keys or values property.

for airportCode in sorted(airports.keys) {
  println("Airport code: \(airportCode)")
}
// Airport code: YYZ
// Airport code: LHR

###Reading - SPL: Control Flow

  • In contrast with switch statements in C and Objective-C, switch statements in Swift do not fall through the bottom of each case and into the next one by default. Instead, the entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit break statement.

  • A switch case can bind the value or values it matches to temporary constants or variables, for use in the body of the case. This is known as value binding.

    let anotherPoint = (2, 0)
    switch anotherPoint {
    case (let x, 0):
      println("on the x-axis with an x value of \(x)")
    case (0, let y):
      println("on the y-axis with a y value of \(y)")
    case let (x, y):
      println("somewhere else at (\(x), \(y))")
    }
    // prints "on the x-axis with an x value of 2"
  • Use where to check for additional conditions.

    let yetAnotherPoint = (1, -1)
    switch yetAnotherPoint {
    case let (x, y) where x == y:
      println("(\(x), \(y)) is on the line x == y")
    case let (x, y) where x == -y:
      println("(\(x), \(y)) is on the line x == -y")
    case let (x, y):
      println("(\(x), \(y)) is just some arbitrary point")
    }
    // prints "(1, -1) is on the line x == -y"
  • Control transfer statements: continue, break, fallthrough, and return.

  • If you really need C-style fallthrough behavior, you can opt in to this behavior on a case-by-case basis with the fallthrough keyword. The example below uses fallthrough to create a textual description of a number:

    let integerToDescribe = 5
    var description = "The number \(integerToDescribe) is"
    switch integerToDescribe {
    case 2, 3, 5, 7, 11, 13, 17, 19:
      description += " a prime number, and also"
      fallthrough
    default:
      description += " an integer."
    }
    println(description)
    // prints "The number 5 is a prime number, and also an integer."
  • Label statements, use label statments combine with control transfer statments to control the flow.

    gameLoop: while square != finalSquare {
      if ++diceRoll == 7 { diceRoll = 1 }
      switch square + diceRoll {
      case finalSquare:
          // diceRoll will move us to the final square, so the game is over
          break gameLoop
      case let newSquare where newSquare > finalSquare:
          // diceRoll will move us beyond the final square, so roll again
          continue gameLoop
      default:
          // this is a valid move, so find out its effect
          square += diceRoll
          square += board[square]
      }
    }

###Reading - SPL: Functions

  • The return value of a function can be ignored when a function without return value is called:

    func printAndCount(stringToPrint: String) -> Int {
      println(stringToPrint)
      return count(stringToPrint)
    }
    func printWithoutCounting(stringToPrint: String) {
      printAndCount(stringToPrint)
    }
    printAndCount("hello, world")
    // prints "hello, world" and returns a value of 12
    printWithoutCounting("hello, world")
    // prints "hello, world" but does not return a value
  • Function with multiple return values

    func minMax(array: [Int]) -> (min: Int, max: Int) {
      var currentMin = array[0]
      var currentMax = array[0]
      for value in array[1..<array.count] {
          if value < currentMin {
              currentMin = value
          } else if value > currentMax {
              currentMax = value
          }
      }
      return (currentMin, currentMax)
    }
    let bounds = minMax([8, -6, 2, 109, 3, 71])
    println("min is \(bounds.min) and max is \(bounds.max)")
    // prints "min is -6 and max is 109"
  • Optional return types

    func minMax(array: [Int]) -> (min: Int, max: Int)? {
      if array.isEmpty { return nil }
      var currentMin = array[0]
      var currentMax = array[0]
      for value in array[1..<array.count] {
          if value < currentMin {
              currentMin = value
          } else if value > currentMax {
              currentMax = value
          }
      }
      return (currentMin, currentMax)
    }
    
    // use optional binding to check whether this 
    // version of the minMax function returns an actual tuple value or nil
    if let bounds = minMax([8, -6, 2, 109, 3, 71]) {
      println("min is \(bounds.min) and max is \(bounds.max)")
    }
    // prints "min is -6 and max is 109"
  • Sometimes it’s useful to name each parameter when you call a function, to indicate the purpose of each argument you pass to the function.

    // External Parameter Names
    func join(string s1: String, toString s2: String, withJoiner joiner: String)
      -> String {
          return s1 + joiner + s2
    }
    join(string: "hello", toString: "world", withJoiner: ", ")
    // returns "hello, world"
  • Shorthand External Parameter Names with #.

    func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
      for character in string {
          if character == characterToFind {
              return true
          }
      }
      return false
    }
    let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
    // containsAVee equals true, because "aardvark" contains a "v"
  • Default Parameter Values.

    func join(string s1: String, toString s2: String,
      withJoiner joiner: String = "-") -> String {
          return s1 + joiner + s2
    }
    
    join(string: "hello", toString: "world")
    // returns "hello-world
  • Variadic Parameters with(...).

    func arithmeticMean(numbers: Double...) -> Double {
      var total: Double = 0
      for number in numbers {
          total += number
      }
      return total / Double(numbers.count)
    }
    arithmeticMean(1, 2, 3, 4, 5)
    // returns 3.0, which is the arithmetic mean of these five numbers
    arithmeticMean(3, 8.25, 18.75)
    // returns 10.0, which is the arithmetic mean of these three numbers
  • Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. Define variable parameters by prefixing the parameter name with the keyword var.

    func alignRight(var string: String, totalLength: Int, pad: Character) -> String {
      let amountToPad = totalLength - count(string)
      if amountToPad < 1 {
          return string
      }
      let padString = String(pad)
      for _ in 1...amountToPad {
          string = padString + string
      }
      return string
    }
    let originalString = "hello"
    let paddedString = alignRight(originalString, 10, "-")
    // paddedString is equal to "-----hello"
    // originalString is still equal to "hello"
  • Variable parameters, as described above, can only be changed within the function itself. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

  • You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an inout parameter.

    func swapTwoInts(inout a: Int, inout b: Int) {
      let temporaryA = a
      a = b
      b = temporaryA
    }
    var someInt = 3
    var anotherInt = 107
    swapTwoInts(&someInt, &anotherInt)
    println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
    // prints "someInt is now 107, and anotherInt is now 3"
  • Function type.

    func printHelloWorld() {
      println("hello, world")
    }
    // Function type: () -> ()
    
    var mathFunction: (Int, Int) -> Int = addTwoInts
    
    // function type as parameter type
    func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
      println("Result: \(mathFunction(a, b))")
    }
    printMathResult(addTwoInts, 3, 5)
    // prints "Result: 8"
    
    // function type as return type
    func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
      return backwards ? stepBackward : stepForward
    }
  • Nested functions.

    func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
      // two nested functions.
      func stepForward(input: Int) -> Int { return input + 1 }
      func stepBackward(input: Int) -> Int { return input - 1 }
      return backwards ? stepBackward : stepForward
    }
    var currentValue = -4
    let moveNearerToZero = chooseStepFunction(currentValue > 0)
    // moveNearerToZero now refers to the nested stepForward() function
    while currentValue != 0 {
      println("\(currentValue)... ")
      currentValue = moveNearerToZero(currentValue)
    }
    println("zero!")
    // -4...
    // -3...
    // -2...
    // -1...
    // zero!

###Reading - SPL: Enumeration

  • Enumeration.

    enum CompassPoint {
      case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
    }
    
    var directionToHead = CompassPoint.West
    
    //  you can set it to a different CompassPoint value using a shorter dot syntax
    directionToHead = .East
  • Matching Enumeration Values with a Switch Statement.

    directionToHead = .South
    switch directionToHead {
      case .North:
        println("Lots of planets have a north")
      case .South:
        println("Watch out for penguins")
      case .East:
        println("Where the sun rises")
      case .West:
        println("Where the skies are blue")
    }
    // prints "Watch out for penguins"
  • Associated Values.

    // This can be read as:
    // “Define an enumeration type called Barcode,
    // which can take either a value of 
    // UPCA with an associated value of type (Int, Int, Int, Int), 
    // or a value of QRCode with an associated value of type String.”
    enum Barcode {
      case UPCA(Int, Int, Int, Int)
      case QRCode(String)
    }
  • Constants and variables of type Barcode can store either a .UPCA or a .QRCode (together with their associated values), but they can only store one of them at any given time.

    switch productBarcode {
    case .UPCA(let numberSystem, let manufacturer, let product, let check):
      println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .QRCode(let productCode):
      println("QR code: \(productCode).")
    }
    // prints "QR code: ABCDEFGHIJKLMNOP."
    
    // If all of the associated values 
    // for an enumeration member are extracted as constants,
    // or if all are extracted as variables, 
    // you can place a single var or let annotation before the member name.
    
    switch productBarcode {
    case let .UPCA(numberSystem, manufacturer, product, check):
      println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
    case let .QRCode(productCode):
      println("QR code: \(productCode).")
    }
    // prints "QR code: ABCDEFGHIJKLMNOP."
  • The barcode example in Associated Values shows how members of an enumeration can declare that they store associated values of different types. As an alternative to associated values, enumeration members can come prepopulated with default values (called raw values), which are all of the same type.

    enum ASCIIControlCharacter: Character {
      case Tab = "\t"
      case LineFeed = "\n"
      case CarriageReturn = "\r"
    }
  • Note that raw values are not the same as associated values. Raw values are set to prepopulated values when you first define the enumeration in your code.

  • The raw value for a particular enumeration member is always the same. Associated values are set when you create a new constant or variable based on one of the enumeration’s members, and can be different each time you do so.

  • Raw values can be strings, characters, or any of the integer or floating-point number types. Each raw value must be unique within its enumeration declaration. When integers are used for raw values, they auto-increment if no value is specified for some of the enumeration members.

    enum Planet: Int {
      case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
    }
    let earthsOrder = Planet.Earth.rawValue
    // earthsOrder is 3
  • Initializing from a Raw Value. If you define an enumeration with a raw-value type, the enumeration automatically receives an initializer that takes a value of the raw value’s type (as a parameter called rawValue) and returns either an enumeration member or nil.

    let possiblePlanet = Planet(rawValue: 7)
    // possiblePlanet is of type Planet? and equals Planet.Uranus
  • Not all possible Int values will find a matching planet, however. Because of this, the raw value initializer always returns an optional enumeration member. In the example above, possiblePlanet is of type Planet?, or “optional Planet.”

  • The raw value initializer is a failable initializer, because not every raw value will return an enumeration member.

###Reading - SPL: Closures

  • Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

  • Closure syntax.

    { (parameters) -> return type in
      statements
    }
  • Because a closure is passed as an argument to a function, Swift can infer the types of its parameters and the type of the value it returns from the type of the function’s parameter.

    reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
    
    // inferring types
    reversed = sorted(names, { s1, s2 in return s1 > s2 } )
  • Advancely, Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration.

    reversed = sorted(names, { s1, s2 in s1 > s2 } )
  • Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.

  • If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body.

    reversed = sorted(names, { $0 > $1 } )
  • There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool.

    reversed = sorted(names, >)
  • Trailing Closures. If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead.

    func someFunctionThatTakesAClosure(closure: () -> ()) {
      // function body goes here
    }
    
    // here's how you call this function without using a trailing closure:
    someFunctionThatTakesAClosure({
      // closure's body goes here
    })
    
    // here's how you call this function with a trailing closure instead:

someFunctionThatTakesAClosure() { // trailing closure's body goes here }

reversed = sorted(names) { $0 > $1 }


```swift
let strings = numbers.map {
  (var number) -> String in
  var output = ""
  while number > 0 {
      output = digitNames[number % 10]! + output
      number /= 10
  }
  return output
}
// strings is inferred to be of type [String]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
  • A closure can capture constants and variables from the surrounding context in which it is defined.

  • In Swift, the simplest form of a closure that can capture values is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.

    func makeIncrementer(forIncrement amount: Int) -> () -> Int {
      var runningTotal = 0
      func incrementer() -> Int {
          runningTotal += amount
          return runningTotal
      }
      return incrementer
    }
    
    let incrementByTen = makeIncrementer(forIncrement: 10)
    incrementByTen()
    // returns a value of 10
    incrementByTen()
    // returns a value of 20
    incrementByTen()
    // returns a value of 30
    
    // If you create a second incrementer, 
    // it will have its own stored reference to a new, separate runningTotal variable.
    
    let incrementBySeven = makeIncrementer(forIncrement: 7)
    incrementBySeven()
    // returns a value of 7
    
    // Calling the original incrementer (incrementByTen) again continues to 
    // increment its own runningTotal variable, 
    // and does not affect the variable captured by incrementBySeven.
    
    incrementByTen()
    // returns a value of 40
  • Closures are feference types. Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. This also means that if you assign a closure to two different constants or variables, both of those constants or variables will refer to the same closure.

    // incrementByTen now returns a value of 40
    let alsoIncrementByTen = incrementByTen
    alsoIncrementByTen()
    // returns a value of 50

###Reading - SPL: Classes and Structures

  • Classes have additional capabilities that structures do not:

    • Inheritance enables one class to inherit the characteristics of another.
    • Type casting enables you to check and interpret the type of a class instance at runtime.
    • Deinitializers enable an instance of a class to free up any resources it has assigned.
    • Reference counting allows more than one reference to a class instance.
  • Definition of Syntax.

    struct Resolution {
      var width = 0
      var height = 0
    }
    class VideoMode {
      var resolution = Resolution()
      var interlaced = false
      var frameRate = 0.0
      var name: String?
    }
    
    // create instance by initializer
    let someResolution = Resolution()
    let someVideoMode = VideoMode()
    
    // Accessing properties
    someVideoMode.resolution.width = 1280
    println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
    // prints "The width of someVideoMode is now 1280"
  • All structures have an automatically-generated memberwise initializer. which you can use to initialize the member properties of new structure instances. This means that any structure and enumeration instances you create —and any value types they have as properties— are always copied when they are passed around in your code. Unlike structures, class instances do not receive a default memberwise initializer.

    let vga = Resolution(width: 640, height: 480)
  • A value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function. All structures and enumerations are value types in Swift.

    let hd = Resolution(width: 1920, height: 1080)
    var cinema = hd
    
    cinema.width = 2048
    
    println("cinema is now \(cinema.width) pixels wide")
    // prints "cinema is now 2048 pixels wide"
    
    println("hd is still \(hd.width) pixels wide")
    // prints "hd is still 1920 pixels wide"
    // The same behavior applies to enumerations
    enum CompassPoint {
      case North, South, East, West
    }
    var currentDirection = CompassPoint.West
    let rememberedDirection = currentDirection
    currentDirection = .East
    if rememberedDirection == .West {
      println("The remembered direction is still .West")
    }
    // prints "The remembered direction is still .West"
  • Classes are reference types.

  • To identity two constants or variables are refer to the same instance of class, use identity operator === or !==.

    if tenEighty === alsoTenEighty {
      println("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
    }
    // prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
  • Unlike Objective-C, There has no explicit pointers in Swift.

  • Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.

  • This behavior is different from NSString, NSArray, and NSDictionary in Foundation, which are implemented as classes, not structures.

  • Choosing Between Classes and Structures. Consider creating a structure when one or more of these conditions apply:

    • The structure’s primary purpose is to encapsulate a few relatively simple data values.
    • It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
    • Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced.
    • The structure does not need to inherit properties or behavior from another existing type.

###Reading - SPL: Properties

  • If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties.

    let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
    // this range represents integer values 0, 1, 2, and 3
    rangeOfFourItems.firstValue = 6
    // this will report an error, even though firstValue is a variable property
  • A stored property is a constant or variable that is stored as part of an instance of a particular class or structure. It could be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword).

  • A azy stored property is a property whose initial value is not calculated until the first time it is used.

     class DataManager {
    		lazy var importer = DataImporter()
     	var data = [String]()
     }
    
     let manager = DataManager()
     manager.data.append("Some data")
     manager.data.append("Some more data")
     // the DataImporter instance for 
     // the importer property has not yet been created.
     
     println(manager.importer.fileName)
     // the DataImporter instance for 
     // the importer property has now been created
     // prints "data.txt"
  • Classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

    struct Rect {
    	var origin = Point()
    	var size = Size()
    	var center: Point {
        	get {
           	let centerX = origin.x + (size.width / 2)
            	let centerY = origin.y + (size.height / 2)
            	return Point(x: centerX, y: centerY)
        	}
        	set(newCenter) {
            	origin.x = newCenter.x - (size.width / 2)
            	origin.y = newCenter.y - (size.height / 2)
        	}
    	}
    }
    var square = Rect(origin: Point(x: 0.0, y: 0.0),
    size: Size(width: 10.0, height: 10.0))
    let initialSquareCenter = square.center
    square.center = Point(x: 15.0, y: 15.0)
    println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
    // prints "square.origin is now at (10.0, 10.0)" 
  • Shorthand Setter Declaration. If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used.

     struct AlternativeRect {
    		var origin = Point()
     	var size = Size()
     	var center: Point {
         	get {
             	let centerX = origin.x + (size.width / 2)
             	let centerY = origin.y + (size.height / 2)
             	return Point(x: centerX, y: centerY)
         	}
         	set {
             	origin.x = newValue.x - (size.width / 2)
             	origin.y = newValue.y - (size.height / 2)
         	}
     	}
     }
  • A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value.

  • You can simplify the declaration of a read-only computed property by removing the get keyword and its braces.

     struct Cuboid {
    		var width = 0.0, height = 0.0, depth = 0.0
     	var volume: Double {
        	return width * height * depth
     	}
     }
  • Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value.

    • willSet is called just before the value is stored.
    • didSet is called immediately after the new value is stored.
  • If you implement a willSet observer, it is passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If no to do so, the parameter will still be made available with a default parameter name of newValue.

  • Similarly, you can name the parameter if you wish, or use the default parameter name of oldValue when you implement didSet observer.

     class StepCounter {
     	var totalSteps: Int = 0 {
         	willSet(newTotalSteps) {
             	println("About to set totalSteps to \(newTotalSteps)")
         	}
         	didSet {
             	if totalSteps > oldValue  {
                 	println("Added \(totalSteps - oldValue) steps")
             	}
         	}
     	}
     }
     let stepCounter = StepCounter()
     stepCounter.totalSteps = 200
     // About to set totalSteps to 200
     // Added 200 steps
     stepCounter.totalSteps = 360
     // About to set totalSteps to 360
     // Added 160 steps
     stepCounter.totalSteps = 896
     // About to set totalSteps to 896
     // Added 536 steps
  • You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.

  • For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only.

  • Stored type properties for value types can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties.

  • You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.

     struct SomeStructure {
     	static var storedTypeProperty = "Some value."
     	static var computedTypeProperty: Int {
         	// return an Int value here
     	}
     }
     enum SomeEnumeration {
     	static var storedTypeProperty = "Some value."
     	static var computedTypeProperty: Int {
         	// return an Int value here
     	}
     }
     class SomeClass {
     	static var storedTypeProperty = "Some value."
     	static var computedTypeProperty: Int {
         	// return an Int value here
     	}
     	class var overrideableComputedTypeProperty: Int {
         	// return an Int value here
     	}
     }
  • Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type.

     struct AudioChannel {
     	static let thresholdLevel = 10
     	static var maxInputLevelForAllChannels = 0
     	var currentLevel: Int = 0 {
         	didSet {
             	if currentLevel > AudioChannel.thresholdLevel {
                 	// cap the new audio level to the threshold level
                 	currentLevel = AudioChannel.thresholdLevel
             	}
             	if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                 	// store this as the new overall maximum input level
                 	AudioChannel.maxInputLevelForAllChannels = currentLevel
             	}
         	}
     	}
     }
    
     var leftChannel = AudioChannel()
     var rightChannel = AudioChannel()
     
     leftChannel.currentLevel = 7
     println(leftChannel.currentLevel)
     // prints "7"
     println(AudioChannel.maxInputLevelForAllChannels)
     // prints "7"
     
     rightChannel.currentLevel = 11
     println(rightChannel.currentLevel)
     // prints "10"
     println(AudioChannel.maxInputLevelForAllChannels)
     // prints "10"

Lecture 3

  • Talk about protocol in Enum, computed properties, optional binding, recursion, Model, passing tail closure to block shorthand.

  • Each enumeration definition defines a brand new type. Like other types in Swift, their names should start with a capital letter.

  • Dictionary always return optional type, a key may not exist.

Lecture 4

  • Optional just another version of Enum.

     var x: String? = nil
     println(x === Optional<String>.None)
     // true
     
     enum Optional<T>{
     	case None
     	case Some(T)
     }
     
     enum Optional<String>{
     	case None
     	case Some(String)
     }
     
     x = "Hello"
     
     println(x == Optional<String>.Some("Hello"))
     // true
  • var x = y! is the same as:

     var y: String? = "Hello"
     
     var x = y!
     // is equivalent to 
     enum Optional<String>{
     	case Some(let value): y = value
     	case None: // raise an exception.
     }
  • NSObject, NSNumber, NSDate, NSData.

  • override and final keyword for methods.

  • Only var can lazy initialize.

  • If a struct has no initializer, it will have default one with all properties as arguments.

###Reading - SPL: Methods

  • Methods are functions that are associated with a particular type. Classes, structures, and enumerations can all define instance methods.

  • Swift gives the first parameter name in a method a local parameter name by default, and gives the second and subsequent parameter names both local and external parameter names by default.

  • You don’t need to define an external parameter name for the first argument value, because its purpose is clear from the function name.

     let counter = Counter()
     counter.incrementBy(5, numberOfTimes: 3)
     // counter value is now 15
  • If you do not want to provide an external name for the second or subsequent parameter of a method, override the default behavior by using an underscore character (_) as an explicit external parameter name for that parameter.

  • Every instance of a type has an implicit property called self, which is exactly equivalent to the instance itself.

     struct Point {
     var x = 0.0, y = 0.0
     	func isToTheRightOfX(x: Double) -> Bool {
         	return self.x > x
     	}
     }
     let somePoint = Point(x: 4.0, y: 5.0)
     if somePoint.isToTheRightOfX(1.0) {
    	 	println("This point is to the right of the line where x == 1.0")
     }
     // prints "This point is to the right of the line where x == 1.0"
     // Without the self prefix, Swift would assume that 
     // both uses of x referred to the method parameter called x.
  • Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

  • The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.

     struct Point {
    		var x = 0.0, y = 0.0
     	mutating func moveByX(deltaX: Double, y deltaY: Double) {
         	x += deltaX
         	y += deltaY
     	}
     }
     var somePoint = Point(x: 1.0, y: 1.0)
     somePoint.moveByX(2.0, y: 3.0)
     println("The point is now at (\(somePoint.x), \(somePoint.y))")
     // prints "The point is now at (3.0, 4.0)"
  • You cannot call a mutating method on a constant of structure type, because its properties cannot be changed, even if they are variable properties.

     let fixedPoint = Point(x: 3.0, y: 3.0)
     fixedPoint.moveByX(2.0, y: 3.0)
     // this will report an error
  • Mutating methods can assign an entirely new instance to the implicit self property.

  • You indicate type methods by writing the keyword static before the method’s func keyword. Classes may also use the class keyword to allow subclasses to override the superclass’s implementation of that method.

  • Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type.

  • A type method can call another type method with the other method’s name, without needing to prefix it with the type name.

  • Similarly, type methods on structures and enumerations can access type properties by using the type property’s name without a type name prefix.

     struct LevelTracker {
     	static var highestUnlockedLevel = 1
     	static func unlockLevel(level: Int) {
         	if level > highestUnlockedLevel { highestUnlockedLevel = level }
     	}
     	static func levelIsUnlocked(level: Int) -> Bool {
         	return level <= highestUnlockedLevel
     	}
     	var currentLevel = 1
     	mutating func advanceToLevel(level: Int) -> Bool {
         	if LevelTracker.levelIsUnlocked(level) {
             	currentLevel = level
             	return true
         	} else {
             	return false
         	}
     	}
     }

###Reading - SPL: Subscripts

  • Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence.

  • Unlike instance methods, subscripts can be read-write or read-only. This behavior is communicated by a getter and setter in the same way as for computed properties.

     subscript(index: Int) -> Int {
     	get {
         	// return an appropriate subscript value here
     	}
     	set(newValue) {
         	// perform a suitable setting action here
     	}
     }
  • Subscript usage:

     struct Matrix {
     	let rows: Int, columns: Int
     	var grid: [Double]
     	init(rows: Int, columns: Int) {
         	self.rows = rows
         	self.columns = columns
         	grid = Array(count: rows * columns, repeatedValue: 0.0)
     	}
     	func indexIsValidForRow(row: Int, column: Int) -> Bool {
         	return row >= 0 && row < rows 
         				&& column >= 0 && column < columns
     	}
     	subscript(row: Int, column: Int) -> Double {
         	get {
             	assert(indexIsValidForRow(row, column: column),
             	 	"Index out of range")
             	return grid[(row * columns) + column]
         	}
         	set {
             	assert(indexIsValidForRow(row, column: column),
             		 "Index out of range")
             	grid[(row * columns) + column] = newValue
         	}
     	}
     }
     
     var matrix = Matrix(rows: 2, columns: 2)
     
     matrix[0, 1] = 1.5
     matrix[1, 0] = 3.2

###Reading - SPL: Inheritance

  • A subclass can provide its own custom implementation of an instance method, type method, instance property, type property, or subscript that it would otherwise inherit from a superclass. This is known as overriding.

  • An overridden method named someMethod() can call the superclass version of someMethod() by calling super.someMethod() within the overriding method implementation.

  • An overridden subscript for someIndex can access the superclass version of the same subscript as super[someIndex] from within the overriding subscript implementation.

  • You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override. You cannot, however, present an inherited read-write property as a read-only property.

  • You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of an inherited property changes, regardless of how that property was originally implemented.

  • You can prevent a method, property, or subscript from being overridden by marking it as final.

  • You can mark an entire class as final by writing the final modifier before the class keyword in its class definition (final class). Any attempt to subclass a final class is reported as a compile-time error.

###Reading - SPL: Initialization

  • If a property always takes the same initial value, provide a default value rather than setting a value within an initializer.

     // Setting Initial Values for Stored Properties
     struct Fahrenheit {
     	var temperature: Double
     	init() {
         	temperature = 32.0
     	}
     }
    
     // Default Property Values
     struct Fahrenheit {
     	var temperature = 32.0
     }
  • Initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called.

  • Swift provides an automatic external name for every parameter in an initializer if you don’t provide an external name yourself. This automatic external name is the same as the local name.

  • If you do not want to use an external name for an initializer parameter, write an underscore (_) instead of an explicit external name for that parameter to override the default behavior.

     struct Color {
     	let red, green, blue: Double
     	init(red: Double, green: Double, blue: Double) {
         	self.red   = red
         	self.green = green
         	self.blue  = blue
     	}
     	init(white: Double) {
         	red   = white
         	green = white
         	blue  = white
     	}
     	init(_ black: Double){
     	
     	}
     }
     
     let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
     let halfGray = Color(white: 0.5)
     
     let veryGreen = Color(0.0, 1.0, 0.0)
     // this reports a compile-time error - external names are required
  • Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.

  • Once a constant property is assigned a value, it can’t be further modified. For class instances, a constant property can only be modified during initialization by the class that introduces it. It cannot be modified by a subclass.

  • The default initializer simply creates a new instance with all of its properties set to their default values. The instance property must be provided default values, otherwise will raise compiler-error.

     class ShoppingListItem {
     	var name: String?
     	var quantity = 1
     	var purchased = false
     	// let y: Int // will raise compile-error
     }
     
     // Default initializer
     var item = ShoppingListItem()
  • Unlike a default initializer, the structure receives a memberwise initializer even if it has stored properties that do not have default values.

     struct Size {
     	var width = 0.0, height = 0.0
     }
     let twoByTwo = Size(width: 2.0, height: 2.0)
  • Initializers can call other initializers to perform part of an instance’s initialization by self.init(). This process, known as initializer delegation, avoids duplicating code across multiple initializers.

  • You can only call self.init from within an initializer.

     struct Rect {
     	var origin = Point()
     	var size = Size()
     	init() {}
     	init(origin: Point, size: Size) {
         	self.origin = origin
         	self.size = size
     	}
     	init(center: Point, size: Size) {
         	let originX = center.x - (size.width / 2)
         	let originY = center.y - (size.height / 2)
         	self.init(origin: Point(x: originX, y: originY), size: size)
     	}
     }
  • Designated Initializers and Convenience Initializers.

  • Designated initializers must always delegate up. Convenience initializers must always delegate across.

    • A designated initializer must call a designated initializer from its immediate superclass.

    • A convenience initializer must call another initializer from the same class.

    • A convenience initializer must ultimately call a designated initializer. It must call self.init(params...) which is a designated initializer.

  • Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error.

  • 4 Safety Check before initialization:

    1. A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.

    2. A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization.

    3. A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn’t, the new value the convenience initializer assigns will be overwritten by its own class’s designated initializer.

    4. An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.

  • Two-Phase Initialization:

    • Phase1:

      • A designated or convenience initializer is called on a class.
      • Memory for a new instance of that class is allocated. The memory is not yet initialized.
      • A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.
      • The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.
      • This continues up the class inheritance chain until the top of the chain is reached.
      • Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.
    • Phase2:

      • Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.
      • Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.
  • Unlike subclasses in Objective-C, Swift subclasses do not inherit their superclass initializers by default.

  • You must write the override modifier before the subclass’s initializer definition. This is true even if you are overriding an automatically provided default initializer.

     class A {
    		func ab(nameA: String){
     		println("A")
     	}
     
     	init(name:String, name2: String) {
        	// same param's Name will be override
        	// by subclass convenience init(name: String, name2: String) 
     	}
     
     	convenience init() {
         	self.init(name: "asa", name2: "asdas")
     	}
     }
    
     class B: A {
     	override func ab(name: String){
         	println("B")
     	}
     	
     	func ab(name: Int){
     		// overloading
     	}
     
     	init(){
         	super.init(name: "XXXB", name2: "asasdaseee")
     	}
     
     	// Need override modifier
     	//convenience init(name: String, name2: String) {
       	// 	self.init()
     	//}
     	
     	// override superclass designated init(name: String, name2: String)
     	override convenience init(name: String, name2: String) {
     		self.init()
     	}
     }
  • Conversely, if you write a subclass initializer that matches a superclass convenience initializer, that superclass convenience initializer can never be called directly by your subclass.

  • As a result, you do not write the override modifier when providing a matching implementation of a superclass convenience initializer.

  • Subclasses do not inherit their superclass initializers by default. However, superclass initializers are automatically inherited if certain conditions are met.

    • Rule1: If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.

    • Rule2: If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition — then it automatically inherits all of the superclass convenience initializers.

  • You write a failable initializer by placing a question mark after the init keyword (init?).

  • A failable initializer creates an optional value of the type it initializes. You write return nil within a failable initializer to indicate a point at which initialization failure can be triggered.

  • Strictly speaking, initializers do not return a value. Rather, their role is to ensure that self is fully and correctly initialized by the time that initialization ends. Although you write return nil to trigger an initialization failure, you do not use the return keyword to indicate initialization success.

     struct Animal {
     	let species: String
     	init?(species: String) {
         	if species.isEmpty { return nil }
         	self.species = species
     	}
     }
     
     let someCreature = Animal(species: "Giraffe")
     // someCreature is of type Animal?, not Animal
    
     if let giraffe = someCreature {
     	println("An animal was initialized with" +
     		" a species of \(giraffe.species)")
     }
     // prints "An animal was initialized with a species of Giraffe"
     
  • You can use a failable initializer to select an appropriate enumeration member based on one or more parameters.

     enum TemperatureUnit {
     	case Kelvin, Celsius, Fahrenheit
     	init?(symbol: Character) {
         	switch symbol {
         	case "K":
             	self = .Kelvin
         	case "C":
         		self = .Celsius
         	case "F":
             	self = .Fahrenheit
         	default:
             	return nil
         	}
     	}
     }
     
     let unknownUnit = TemperatureUnit(symbol: "X")
     if unknownUnit == nil {
     	println("This is not a defined temperature unit," +
     		 " so initialization failed.")
     }
     // prints "This is not a defined temperature unit,
     // so initialization failed."
  • Enumerations with raw values automatically receive a failable initializer, init?(rawValue:), that takes a parameter called rawValue of the appropriate raw-value type and selects a matching enumeration member if one is found, or triggers an initialization failure if no matching value exists.

     enum TemperatureUnit: Character {
     	case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
     }
    
     let unknownUnit = TemperatureUnit(rawValue: "X")
     if unknownUnit == nil {
     	println("This is not a defined temperature unit, " +
     	 "so initialization failed.")
     }
     // prints "This is not a defined temperature unit, 
     // so initialization failed."
  • For classes, however, a failable initializer can trigger an initialization failure only after all stored properties introduced by that class have been set to an initial value and any initializer delegation has taken place.

     class Product {
     	let name: String!
     	init?(name: String) {
     	  	// must provide self.name to set initial value
         	self.name = name
         	if name.isEmpty { return nil }
     	}
     }
  • A failable initializer of a class, structure, or enumeration can delegate across to another failable initializer from the same class, structure, or enumeration. Similarly, a subclass failable initializer can delegate up to a superclass failable initializer. Use self.init() or super.init().

     class CartItem: Product {
        let quantity: Int!
    		init?(name: String, quantity: Int) {
         	self.quantity = quantity
         	super.init(name: name)
         	if quantity < 1 { return nil }
     	}
     }
  • You can override a failable initializer with a nonfailable initializer but not the other way around.

     class Document {
     	var name: String?
     	// this initializer creates a document with a nil name value
     	init() {}
     	// this initializer creates a document with a non-empty name value
     	init?(name: String) {
         	self.name = name
         	if name.isEmpty { return nil }
     	}
     }
     
     class AutomaticallyNamedDocument: Document {
     	override init() {
         	super.init()
         	self.name = "[Untitled]"
     	}
     	// override superclass' failable initializer
     	// Identify by its paramerter list and names.
     	override init(name: String) {
         	super.init()
         	if name.isEmpty {
             	self.name = "[Untitled]"
         	} else {
             	self.name = name
         	}
     	}
     }
  • You typically define a failable initializer that creates an optional instance of the appropriate type by placing a question mark after the init keyword (init?). You can define a failable initializer that creates an implicitly unwrapped optional instance of the appropriate type. (init!) return non-optional instance instead.

  • You can delegate from init? to init! and vice versa, and you can override init? with init! and vice versa. You can also delegate from init to init!, although doing so will trigger an assertion if the init! initializer causes initialization to fail.

  • Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer:

  • You must also write the required modifier before every subclass implementation of a required initializer.

     class SomeClass {
     	required init() {
         	// initializer implementation goes here
     	}
     }
     
     class SomeSubclass: SomeClass {
     	required init() {
         	// subclass implementation of the required initializer goes here
     	}
     }
  • If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property.

  • Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.

     class SomeClass {
     	let someProperty: SomeType = {
         	// create a default value for someProperty inside this closure
         	// someValue must be of the same type as SomeType
         	return someValue
         }()
     }
     struct Checkerboard {
     	let boardColors: [Bool] = {
         	var temporaryBoard = [Bool]()
         	var isBlack = false
         	for i in 1...10 {
             	for j in 1...10 {
                 	temporaryBoard.append(isBlack)
                 	isBlack = !isBlack
             	}
             	isBlack = !isBlack
         	}
         	return temporaryBoard
         	}()
     	func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
         	return boardColors[(row * 10) + column]
     	}
     }
     
     // Whenever a new Checkerboard instance is created,
     // the closure is executed, and the default value of boardColors is
     // calculated and returned. 
     
     let board = Checkerboard()
     println(board.squareIsBlackAtRow(0, column: 1))
     // prints "true"
     println(board.squareIsBlackAtRow(9, column: 9))
     // prints "false"

###Reading - SPL: Optional Chaining

  • Optional chaining as an alternative to forced unwrapping.

     class Person {
     	var residence: Residence?
     }
    
     class Residence {
     	var numberOfRooms = 1
     }
     
     // forced unwrapping using ! operator
     let roomCount = john.residence!.numberOfRooms
     // this triggers a runtime error when 
     // residence is nil
     
     // use optional chaining
     let roomCount = john.residence?.numberOfRooms
  • The optional chaining attempt returns a "optional Int”. When residence is nil, as in the example above, this optional Int will also be nil, to reflect the fact that it was not possible to access numberOfRooms.

  • The fact that it is queried through an optional chain means that the call to numberOfRooms will always return an Int? instead of an Int.

  • You can use optional chaining with calls to properties, methods, and subscripts that are more than one level deep.

     class Person {
     	var residence: Residence?
     }
     
     class Residence {
     	var rooms = [Room]()
     	var numberOfRooms: Int {
         	return rooms.count
     	}
     	subscript(i: Int) -> Room {
         	get {
           	  return rooms[i]
         	}
         	set {
            	 rooms[i] = newValue
         	}
     	}
     	func printNumberOfRooms() {
         	println("The number of rooms is \(numberOfRooms)")
     	}
     	var address: Address?
     }
     
     let john = Person()
     if let roomCount = john.residence?.numberOfRooms {
     	println("John's residence has \(roomCount) room(s).")
     } else {
     	println("Unable to retrieve the number of rooms.")
     }
     // prints "Unable to retrieve the number of rooms."
     
     let someAddress = Address()
     someAddress.buildingNumber = "29"
     someAddress.street = "Acacia Road"
     
     john.residence?.address = someAddress
     // assgined failed cuz john.residence is nil.
     // will return nil.
  • You can use optional chaining to call a method on an optional value, and to check whether that method call is successful. You can do this even if that method does not define a return value.

  • Functions and methods with no return type have an implicit return type of Void. This means that they return a value of (), or an empty tuple.

  • If you call this method on an optional value with optional chaining, the method’s return type will be Void?, not Void, because return values are always of an optional type when called through optional chaining.

  • Any attempt to set a property through optional chaining returns a value of type Void?, which enables you to compare against nil to see if the property was set successfully.

     if (john.residence?.address = someAddress) != nil {
     	println("It was possible to set the address.")
     } else {
     	println("It was not possible to set the address.")
     }
     // prints "It was not possible to set the address."
    
     println((john.residence?.printNumberOfRooms()).dynamicType)	// Swift.Optional<()>
     println((john.residence?.address).dynamicType)
     // Swift.Optional<main.Address>
  • Use optional chaining in supscript syntax.

     if let firstRoomName = john.residence?[0].name {
     	println("The first room name is \(firstRoomName).")
     } else {
     	println("Unable to retrieve the first room name.")
     }
     // prints "Unable to retrieve the first room name."
     
     john.residence?[0] = Room(name: "Bathroom")
     
     println(john.residence?[0])
     // got nil too
  • If a subscript returns a value of optional type—such as the key subscript of Swift’s Dictionary type—place a question mark after the subscript’s closing bracket to chain on its optional return value.

     var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
     testScores["Dave"]?[0] = 91
     testScores["Bev"]?[0]++
     testScores["Brian"]?[0] = 72
     // the "Dave" array is now [91, 82, 84] 
     // and the "Bev" array is now [80, 94, 81]
  • Linking Multiple Levels of Chaining:

    1. If the type you are trying to retrieve is not optional, it will become optional because of the optional chaining.
    2. If the type you are trying to retrieve is already optional, it will not become more optional because of the chaining.
    3. If you try to retrieve an Int value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.
    4. Similarly, if you try to retrieve an Int? value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.
     if let johnsStreet = john.residence?.address?.street {
     	println("John's street name is \(johnsStreet).")
     } else {
     	println("Unable to retrieve the address.")
     }
     // prints "Unable to retrieve the address."
     
     
     let johnsAddress = Address()
     johnsAddress.buildingName = "The Larches"
     johnsAddress.street = "Laurel Street"
     john.residence!.address = johnsAddress
    
     if let johnsStreet = john.residence?.address?.street {
         println("John's street name is \(johnsStreet).")
     } else {
     	println("Unable to retrieve the address.")
     }
     // prints "John's street name is Laurel Street."
     
     // The type of street property is String?.
     // The return value of john.residence?.address?.street 
     // is therefore also String?
  • Note the use of an exclamation mark during the assignment of an address instance to john.residence.address. The john.residence property has an optional type, and so you need to unwrap its actual value with an exclamation mark before accessing the residence’s address property.

###Reading - SPL: Type Casting

class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}
 
class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}

let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// the type of "library" is inferred to be [MediaItem]
  • Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.

     var movieCount = 0
     var songCount = 0
    
     for item in library {
     	if item is Movie {
         	++movieCount
     	} else if item is Song {
         	++songCount
     	}
     }
    
     println("Media library contains \(movieCount)" + 
     	"movies and \(songCount) songs")
     // prints "Media library contains 2 movies and 3 songs"
  • Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as? or as!).

  • Because downcasting can fail, the type cast operator comes in two different forms.

  • The forced form, as!, attempts the downcast and force-unwraps the result as a single compound action.

  • This form (as!) of the operator will trigger a runtime error if you try to downcast to an incorrect class type.

     for item in library {
         if let movie = item as? Movie {
         	println("Movie: '\(movie.name)', dir. \(movie.director)")
     	} else if let song = item as? Song {
         	println("Song: '\(song.name)', by \(song.artist)")
     	}
     }
    
     // Movie: 'Casablanca', dir. Michael Curtiz
     // Song: 'Blue Suede Shoes', by Elvis Presley
     // Movie: 'Citizen Kane', dir. Orson Welles
     // Song: 'The One And Only', by Chesney Hawkes
     // Song: 'Never Gonna Give You Up', by Rick Astley
  • Swift provides two special type aliases for working with non-specific types:

    1. AnyObject can represent an instance of any class type.
    2. Any can represent an instance of any type at all, including function types.
  • When working with Cocoa APIs, it is common to receive an array with a type of [AnyObject], or “an array of values of any object type”. This is because Objective-C does not have explicitly typed arrays.

     let someObjects: [AnyObject] = [
     	Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
     	Movie(name: "Moon", director: "Duncan Jones"),
     	Movie(name: "Alien", director: "Ridley Scott")
     ]
     
     for object in someObjects {
     	let movie = object as! Movie
     	println("Movie: '\(movie.name)', dir. \(movie.director)")
     }
    
     // Or rewrite as
     for movie in someObjects as! [Movie] {
     	println("Movie: '\(movie.name)', dir. \(movie.director)")
     }
  • You can use the is and as operators in a switch statement’s cases to discover the specific type of a constant or variable that is known only to be of type Any or AnyObject.

     var things = [Any]()
    
     things.append(0)
     things.append(0.0)
     things.append(42)
     things.append(3.14159)
     things.append("hello")
     things.append((3.0, 5.0))
     things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
     // function type -> closure
     things.append({ (name: String) -> String in "Hello, \(name)" })
     
     for thing in things {
     	switch thing {
     	case 0 as Int:
         	println("zero as an Int")
     	case 0 as Double:
         	println("zero as a Double")
     	case let someInt as Int:
         	println("an integer value of \(someInt)")
     	case let someDouble as Double where someDouble > 0:
         	println("a positive double value of \(someDouble)")
     	case is Double:
         	println("some other double value that I don't want to print")
     	case let someString as String:
         	println("a string value of \"\(someString)\"")
     	case let (x, y) as (Double, Double):
         	println("an (x, y) point at \(x), \(y)")
     	case let movie as Movie:
         	println("a movie called '\(movie.name)'," +
         		"dir. \(movie.director)")
     	case let stringConverter as String -> String:
         	println(stringConverter("Michael"))
     	default:
         	println("something else")
     	}
     }
    
     // zero as an Int
     // zero as a Double
     // an integer value of 42
     // a positive double value of 3.14159
     // a string value of "hello"
     // an (x, y) point at 3.0, 5.0
     // a movie called 'Ghostbusters', dir. Ivan Reitman
     // Hello, Michael

###Reading - SPL: Nested Types

  • Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support.

    struct BlackjackCard {
    
    	// nested Suit enumeration
    	enum Suit: Character {
        	case Spades = "", Hearts = "", Diamonds = "", Clubs = ""
    	}
    
    	// nested Rank enumeration
    	enum Rank: Int {
        	case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        	case Jack, Queen, King, Ace
        	struct Values {
            	let first: Int, second: Int?
        	}
        	var values: Values {
            	switch self {
            	case .Ace:
                	return Values(first: 1, second: 11)
            	case .Jack, .Queen, .King:
                	return Values(first: 10, second: nil)
            	default:
                	return Values(first: self.rawValue, second: nil)
            	}
        	}
    	}
    
    	// BlackjackCard properties and methods
    	let rank: Rank, suit: Suit
    	var description: String {
        	var output = "suit is \(suit.rawValue),"
        	output += " value is \(rank.values.first)"
        	if let second = rank.values.second {
            	output += " or \(second)"
        	}
        	return output
    	}
    }
    
    let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
    println("theAceOfSpades: \(theAceOfSpades.description)")
    // prints "theAceOfSpades: suit is ♠, value is 1 or 11"
  • We can also refer to nested types.

     let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue
     // heartsSymbol is "♡"

###Reading - SPL: Deinitialization

  • Swift automatically deallocates your instances when they are no longer needed, to free up resources.

  • Typically you don’t need to perform manual clean-up when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional clean-up yourself.

  • If you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.

  • Deinitializers are called automatically, just before instance deallocation takes place.

  • You are not allowed to call a deinitializer yourself. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even if a subclass does not provide its own deinitializer.

  • Deinitializers in action:

     struct Bank {
     	static var coinsInBank = 10_000
     	static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
         	numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
         	coinsInBank -= numberOfCoinsToVend
         	return numberOfCoinsToVend
     	}
     	static func receiveCoins(coins: Int) {
         	coinsInBank += coins
     	}
     }
     
     class Player {
     	var coinsInPurse: Int
     	init(coins: Int) {
         	coinsInPurse = Bank.vendCoins(coins)
     	}
     	func winCoins(coins: Int) {
         	coinsInPurse += Bank.vendCoins(coins)
     	}
     	deinit {
         	Bank.receiveCoins(coinsInPurse)
     	}
     }
     
     var playerOne: Player? = Player(coins: 100)
     println("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
     // prints "A new player has joined the game with 100 coins"
     println("There are now \(Bank.coinsInBank) coins left in the bank")
     // prints "There are now 9900 coins left in the bank"
     
     playerOne!.winCoins(2_000)
     println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
     // prints "PlayerOne won 2000 coins & now has 2100 coins"
     println("The bank now only has \(Bank.coinsInBank) coins left")
     // prints "The bank now only has 7900 coins left"
     
     playerOne = nil
     println("PlayerOne has left the game")
     // prints "PlayerOne has left the game"
     println("The bank now has \(Bank.coinsInBank) coins")
     // prints "The bank now has 10000 coins"
  • The player has now left the game. This is indicated by setting the optional playerOne variable to nil, meaning “no Player instance.” At the point that this happens, the playerOne variable’s reference to the Player instance is broken. No other properties or variables are still referring to the Player instance, and so it is deallocated in order to free up its memory.

##To Read List 7/23/2015

  1. Automatic Reference Counting
  2. Extensions
  3. Protocol
  4. Generics
  5. Access Control
  6. Advanced Operators
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment