Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intro to Swift

Intro to Swift

A quick introduction to Apple's new programming language for iOS and OSX.

Joe R. Smith

October 21, 2014
Tweet

More Decks by Joe R. Smith

Other Decks in Programming

Transcript

  1. Swift Apple's new programming language for iOS and OS X

    Joe R. Smith 10-21-2014 Coffee & Code Omaha
  2. –Peter Landin “Most papers in computer science describe how their

    author learned what someone else already knew.”
  3. Design Goals • Modern Language Features • Fast/Powerful Systems &

    Application Development • Rapid, Iterative Development • Ready, Now: Minimize or Eliminate Barriers to Adoption • Evolvable
  4. Modern • Type Inference • Closures and first-class functions •

    Tuples, multiple return values • Optionals, Enums (the real deal) • Extensions, Protocols • Pattern matching • Generics • Functional idioms (map, filter, etc.)
  5. Modern • Type Inference • Closures and first-class functions •

    Tuples, multiple return values • Optionals, Enums (the real deal) • Extensions, Protocols • Pattern matching • Generics • Functional idioms (map, filter, etc.)
  6. Fast & Powerful • LLVM compiler/Toolchain • Genuinely C-like performance

    • Automatic Reference Counting (ARC) • Safely Typed • Semantically, Strong + Static Typing • Strict type interfaces with subtype polymorphism • Consistent Semantics around Mutability • Much of the language built in itself 7 implementation inheritance
  7. Rapid Iteration • Read Eval Print Loop (REPL) • LLDB

    • Command line • Playgrounds • Minimal boilerplate
  8. Ready, Now • iOS 7 + • OS X 10.9

    + • Interoperable with Objective-C libraries • Full Cocoa/Cocoa Touch Framework compatibility
  9. Constants Immutable as a brick Declaration let launchCode: String =

    "000000" Declaration with Type Inference (inferred to be of type Int) let maxLaunchAttempts = 10
  10. Variables A variable's value can change, its Type cannot Declaration,

    with Type Inference (Inferred to be an Int and must always hold an Int) var launchAttempt = 3 Mutate! launchAttempt += 1 // launchAttempt now equals 4
  11. Numbers Number are "Named" Types Signed and unsigned Int variations

    (e.g. Int32, UInt16, etc) UInt8.max // 255 Int.max // 9,223,372,036,854,775,807 32-bit Float and 64-bit Double let pi = 3.14159 // Inferred as Double
  12. Numbers Exponents let atomsInTheObservableUniverse = 10e82 Bases let decimal =

    255 let octal = 0o377 let binary = 0b11111111 let hex = 0xff Delimiters let readableLargeInt = 10_234_567 // 10,234,567
  13. Strings Mutability determined by let/var Interpolation, immutable String let attemptMessage

    = 
 "There are \(maxLaunchAttempts - launchAttempt) launch attempts remaining!" // "There are 7 launch attempts remaining!" Concatenation, mutable String var warningMessage = "Warning: " + attemptMessage warningMessage += "!!" // "Warning: There are 7 launch attempts remaining!!!"
  14. Strings Mutability determined by let/var Copy on write var baz

    = "Simple things" let quux = baz baz += " should be simple" baz // "Simple things should be simple" quux // "Simple things"
  15. Tuples Compound values Indexed fields let person: (String, String, Int)

    = ("Joe", "Smith", 30) person.0 // "Joe" person.2 // 30 Named fields let person2: (first: String, last: String, age: Int) = (first: "Joe", last: "Smith", age: 30) person2.first // "Joe" person2.last // "Smith"
  16. Tuples Compound values Indexed fields let person = ("Joe", "Smith",

    30) person.0 // "Joe" person.2 // 30 Named fields let person2 = (first: "Joe", last: "Smith", age: 30) person2.first // "Joe" person2.last // "Smith"
  17. • Non-optional variables cannot be nil. • Optional types must

    be used when a variable might not contain a value, i.e. should be settable to `nil`. • Optionals are represented as a Type followed by `?` • e.g.: String? Optionals
  18. Optionals All vars must be initialized or Optional Optionals must

    be unwrapped to access their values. if (lastAttemptedLaunchCode != nil) { var code = lastAttemptedLaunchCode! println("Launch Code Entered: \(code)") } Declare an optional variable var lastAttemptedLaunchCode: String? // initialized to nil lastAttemptedLaunchCode = "123456" // {Some "123456"} explicit unwrapping
  19. Optionals Optional binding can be used in an `if let`

    statement to conditionally and implicitly unwrapped and assign its value if let code = lastAttemptedLaunchCode { println("Launch Code Entered: \(code)") }
  20. Collections • Two built-in collection types: Arrays and Dictionaries •

    Homogeneous • Mutable and immutable varieties • Declared using let/var • Implement the Sequence Protocol
  21. Arrays Immutable Array Literal let dataSample: [Double] = [1.2, 4.32,

    6.7, 7.22, 9.01] let samples: [[Double]] = [[1.9, 3.2, 4.5], [6.0], dataSample] // [[1.9, 3.2, 4.5], [6.0], [1.2, 4.32, 6.7, 7.22, 9.01]] samples.count // 3 dataSample.sorted(>) // [9.01, 7.22, 6.7, 4.32, 1.2]
  22. Arrays Mutable Concatenate another Array languages += ["Common Lisp", "Smalltalk",

    "Ruby"] // ["Forth", "Common Lisp", "Smalltalk", "Ruby"] Initialize var languages: [String] = [] Append a value languages.append("Forth") // ["Forth"]
  23. Dictionaries Immutable Dictionary Literal let phoneMarketShareApril = ["Apple": 41.4, "Samsung":

    27.0, "LG": 6.7, "Motorola": 6.4, "HTC": 5.4] Looking up a Key always returns an Optional let appleMarketShare: Double? = phoneMarketShareApril["Apple"] // {Some 41.4}
  24. Dictionaries Mutable (all the way down) Mutate the value of

    a key, in place languageInfluences["Swift"]!.append("Ruby") // ["Swift": ["Objective-C", "Rust", "Haskell", "D", "Python", "Scala", "C#", "CLU", "Ruby"]] Initialize var languageInfluences: [String: [String]] = [:] Add a Key/Value languageInfluences["Swift"] = ["Objective-C", "Rust", "Haskell", "D", "Python", "Scala", "C#", "CLU"] // ["Swift": ["Objective-C", "Rust", "Haskell", "D", "Python", "Scala", "C#", "CLU"]]
  25. Branching if/else, no surprises if/else, Conditions must evaluate to `true`

    or `false` if condition { statements ... } else if condition { statements ... } else { yup ... }
  26. Branching Case statements can switch on more than Integers let

    command = "launch" switch command { case "launch", "l": println("Fire the missiles!") case "abort", "a": println("Aborting launch, just kidding! Launch!") default: println("Did you mean: launch?") }
  27. Branching Case pattern matching let rgb = (50, 50, 255)

    switch rgb { case (0, 255, 0): println("green") case (255, 255, _) println("shade of yellow") case (let r, 0, 0): println("Just red with a value of \(r)") case let (r, g, b) where r == g && g == b: println("shade of grey") default: println("Some other color") }
  28. Iteration All the usual suspects for assignments; condition; increment {

    statements... } while condition { statements... } do { } while true for item in collection { statements... }
  29. Iteration For Each Destructuring let coordinates = [(3, 4), (8,

    2), (3, 9)] for (x, y) in coordinates { println("x: \(x), y: \(y)") }
  30. Functions and Closures • Functions are first-class • Functions can

    be nested • Optional external parameter names 
 (like Objective-C) • All Functions (in Swift) are Closures
  31. Functions and Closures Declaration Function func name(arg1: Type, arg2: Type

    ...) -> ReturnType { Statements... return ofReturnType } Closure { (arg1: Type, arg2: Type ...) -> ReturnType in Statements... }
  32. Functions Simple Function func factorial(num: Int) -> Int { var

    acc = 1 for n in 1...num { acc *= n } return acc } factorial(5) // 120
  33. Functions Functions are first-class let myFunc = factorial myFunc(12) //

    479,001,600 let incrementByTwo = { (n:Int) -> Int in n + 2 }
  34. Functions Higher Order Functions Function that makes a function/closure as

    an argument func iterate(value: Int, iterations: Int,fn: ((Int) -> Int)) -> Int { var acc = value for _ in 0 ..< iterations { acc = fn(acc) } return acc } Pass a Function as an argument iterate(50, 25, incrementByTwo) // 100
  35. Functions Higher Order Functions Pass a Function, inline iterate(2, 5,

    {n in n * 3}) // 486 Trailing Closure syntactic sugar iterate(2, 5) { n in n * 3 } // 486
  36. Functions Higher Order Functions let quuux = [1, 2, 5,

    4, 3] Double each value using map let doubled = quuux.map({n in n * 2}) // [2, 4, 10, 8, 6] Get only even Ints using filter let evens = quuux.filter({$0 % 2 == 0}) // [2, 4] Get the sum of the Ints in the array using reduce let sum = quuux.reduce(0, +) // 15
  37. Closures Functions are Closures Function that returns a Closure func

    makeIdGenerator(prefix: String, startNum: Int) -> (() -> String){ var id = startNum return { () -> String in prefix + "\(id++)" } } let genId = makeIdGenerator("widget", 5) genId() // "widget5" genId() // "widget6" genId() // "widget7"
  38. Functions Multiple Return Values Function that returns a tuple func

    minMaxInt(a:[Int]) -> (min: Int, max: Int) { var currentMin = Int.max var currentMax = Int.min for i in a { currentMin = min(currentMin, i) currentMax = max(currentMax, i) } return (min: currentMin, max: currentMax) }
  39. Functions Multiple Return Values let myArray = [5, 4, 8,

    12, 100, 765, -45, 3] let minMaxResult = minMaxInt(myArray) minMaxResult.min // -45 minMaxResult.min // 765 let (arrayMin, arrayMax) = minMaxInt(myArray) arrayMin // -45 arrayMax // 765
  40. Functions External Parameter Names func polarToCartesian(radius r:Double, angle a:Double) ->

    (x: Double, y: Double) { let angleRadians = a * pi / 180 return (x: r * cos(angleRadians), y: r * sin(angleRadians)) } external names let cartesianCoordinates = polarToCartesian(radius: 7.2, angle: 25) cartesianCoordinates.x // 6.52541718811894 cartesianCoordinates.y // 3.04284907956374 let (xCoordinate, yCoordinate) = polarToCartesian(radius: 7.2, angle: 25)
  41. Functions External Parameter Names Same external and internal parameter names

    func greeter(#firstName: String, #lastName: String) { println("Hello \(firstName) \(lastName)!") } greeter(firstName: "Swift", lastName: "User") // Hello Swift User!
  42. Enumerations Enumerations are first class enum HTTPMethod { case POST,

    PUT, PATCH, GET, OPTIONS, HEAD, DELETE, TRACE, CONNECT } let anHTTPMethod = HTTPMethod.POST var anotherHTTPMethod: HTTPMethod anotherHTTPMethod = .OPTIONS
  43. Enumerations Enumeration types can have a raw value type Enumeration

    with a raw type of Int enum HTTPCode: Int { case OK = 200 case Created = 201 case Accepted = 202 case MovedPermanently = 301 case BadRequest = 400 case Unauthorized = 401 case NotFound = 404 case IAmATeapot = 418 }
  44. Enumerations Enumeration types can have a raw value type Converting

    an Enum value to its raw representation let responseDict = ["status": HTTPCode.IAmATeapot.toRaw(), "body": "short and stout"] Note: Because I created a Dictionary with multiple keyval types, Swift's type inference inferred it as having a type [String: AnyObject?] Enumeration with a raw type of Int enum HTTPCode: Int { case OK = 200 case Created = 201 case Accepted = 202 case MovedPermanently = 301 case BadRequest = 400 case Unauthorized = 401 case NotFound = 404 case IAmATeapot = 418 }
  45. Enumerations Enumeration types can have a raw value type if

    let code = responseCode { switch code { case .OK, .Created, .Accepted: println("Success! ") case .BadRequest, .Unauthorized, .NotFound: println("Something went wrong, ") case .IAmATeapot: println("Wtf? ") default: println("Something else happened... ") } } Creating an Enum form its raw representation (always returns an optional) let responseCode: HTTPCode? = HTTPCode.fromRaw(418) Enumeration with a raw type of Int enum HTTPCode: Int { case OK = 200 case Created = 201 case Accepted = 202 case MovedPermanently = 301 case BadRequest = 400 case Unauthorized = 401 case NotFound = 404 case IAmATeapot = 418 }
  46. Enumerations Sequential raw values are implicit enum OSILayer: Int {

    case DataLink = 1, Network, Transport, Session, Presentation, Application } if let layer = OSILayer.fromRaw(5) { layer == OSILayer.Presentation // true }
  47. Enumerations Associated Values of any type enum LaunchCode { case

    SixDigit(Int, Int, Int, Int, Int, Int) case Complex(String) // assume alphanumeric } var lc: LaunchCode? lc = .SixDigit(4, 8, 6, 7, 7, 2) switch lc! { case .SixDigit: println("Can be cracked in \(10e6 / 2) attempts, on average") case .Complex(let passcode): println("Can be cracked in \(pow(36.0, Double(countElements(passcode))))") }
  48. Structures and Classes • Structures are Value Types (and therefore

    passed by value) • Classes are Reference Types • Structure and Class methods *are* functions that close over the Structure or Class instance variables • Fundamental Types in Swift are built from Structures (e.g., Arrays, Dictionaries, etc.)
  49. Structures Structure declaration Simple struct declaration struct HistInt { var

    value: Int let maxHistoryLength: Int var history: [Int] } If you don't provide an initializer, a default initializer is generated with named parameters let myHistInt = HistInt(value: 3, maxHistoryLength: 5, history: []) Note: This is an immutable struct (i.e., cannot set `value`, because the HistInt instance is assigned to a constant)
  50. Structures Implementing an initializer With a basic initializer (you must

    initialize all uninitialized lets/vars) struct HistInt2 { var value: Int let maxHistoryLength:Int var history:[Int] = [] init(initialValue: Int, maxHistoryLength: Int) { self.value = initialValue self.maxHistoryLength = maxHistoryLength history = [] } }
  51. Structures Advanced struct HistInt3 { let maxHistoryLength:Int private var history:[Int]

    = [] var value: Int { willSet(newVal) { if (history.count == maxHistoryLength) { history.removeAtIndex(0) history.append(value) } else { history.append(value) } } } var historyLength:Int { get { return history.count } } init(initialValue: Int, maxHistoryLength: Int) { value = initialValue self.maxHistoryLength = maxHistoryLength history = [] } func calcAverage() -> Double { return history.reduce(0.0, {$0 + Double($1)}) / Double(history.count) } mutating func resetHistory() { history = [] } } instance methods Computed Property Property with Observer Property with Access Modifier
  52. Structures Let's test it! struct HistInt3 { let maxHistoryLength:Int private

    var history:[Int] = [] var value: Int { willSet(newVal) { if (history.count == maxHistoryLength) { history.removeAtIndex(0) history.append(value) } else { history.append(value) } } } var historyLength:Int { get { return history.count } } init(initialValue: Int, maxHistoryLength: Int) { value = initialValue self.maxHistoryLength = maxHistoryLength history = [] } func calcAverage() -> Double { return history.reduce(0.0, {$0 + Double($1)}) / Double(history.count) } mutating func resetHistory() { history = [] } } var myHistInt3 = HistInt3(initialValue: 5, maxHistoryLength: 4) myHistInt3.value = 2 myHistInt3.value = 7 myHistInt3.value = 12 myHistInt3.value = 1 myHistInt3.calcAverage() // 6.5
  53. Structures Subscripts subscript(index: Int) -> Int? { get { if

    history.count > index { return history[index] } else { return nil } } } myHistInt3[2]! // 7
  54. Classes Declaration class Task: ListItem, Completable { var name, description:

    String var completed = false let createdDate: NSDate var dueDate: NSDate? init(name: String, withDescription aDescription: String, andDueDate aDate: NSDate?) { self.createdDate = NSDate() // now self.name = name self.description = aDescription self.dueDate = aDate } convenience init(name: String, withDescription aDescription: String) { self.init(name: name, withDescription:aDescription, andDueDate:nil) } func sync() { println("Does not support synchronization with a server") } } Protocols Convenience initializer Designated initializer
  55. Classes Declaration Must initialize subclass vars before calling super.init class

    BugTask: Task { let relatedTask: Task? init(name: String, withDescription aDescription: String, andRelatedTask aTask: Task) { self.relatedTask = aTask super.init(name: name, withDescription: aDescription, andDueDate: nil) } override func sync() { // ... sync code here ;) } } override a superclass function
  56. Classes Instantiation let myTask = Task(name: "Swift Presentation", withDescription: "Coffee

    and Code", andDueDate:date) let myBug = BugTask(name: "Slide code compilation error", withDescription: "code on slide 34 does not compile", andRelatedTask: myTask) let date:NSDate? = { var dateComponents = NSDateComponents() dateComponents.year = 2014 dateComponents.month = 10 dateComponents.day = 21 dateComponents.hour = 0 dateComponents.minute = 0 dateComponents.second = 0 return NSCalendar.currentCalendar().dateFromComponents(dateComponents) }()
  57. Protocols Define Interface Types Recall class Task: ListItem, Completable protocol

    ListItem { var name: String { get } } protocol Completable { var completed: Bool { get set } var dueDate: NSDate? { get set } func sync() }
  58. Protocols Define Interface Types Add objects conforming to ListItem to

    an array of type [ListItem] var myListItems:[ListItem] = [myTask, myBug] Iterate over ListItems for item in myListItems { println(item.name) } // Swift Presentation // Slide code compilation error
  59. Extensions Add properties and methods to existing Types Extend the

    ListItem Protocol to Strings extension String: ListItem { var name: String { return self } } var anotherTask = "Drink more coffee" anotherTask.name // "Drink more coffee myListItems.append(anotherTask)
  60. Optional Chaining Navigate properties, methods, and subscripts that might return

    Optionals let myThings = ["bugs": [myBug]] if let myBugs = myThings["bugs"] { if let bug = myBugs.first { if let relatedTask = bug.relatedTask { if let dueDate = relatedTask.dueDate { println("\(dueDate)") } } } }
  61. Optional Chaining Navigate properties, methods, and subscripts that might return

    Optionals if let dueDate = myThings["bugs"]?.first?.relatedTask?.dueDate { println("\(dueDate)") }
  62. Generics Parametric Polymorphism func iterate<T>(value: T, iterations: Int, fn: (T

    -> T)) -> T { var acc = value for _ in 0 ..< iterations { acc = fn(acc) } return acc }
  63. There's more! Automatic Reference Counting Operator Overloading Custom Operators Objective-C

    Interop Lazy initialization Lazy initialization Nested Types Modules Associated Types Safe Type Casting / Downcasting Delegation Deinitialization Type Constraints