Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

@subdigital

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Objec&ve(C

Slide 6

Slide 6 text

[ ]

Slide 7

Slide 7 text

2009

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

C#

Slide 11

Slide 11 text

BCSItem *item = [[BCSItem alloc] initWithIdentifier:@"id1"]; [item favorite];

Slide 12

Slide 12 text

°□°#

Slide 13

Slide 13 text

NSFileManager *fm = [NSFileManager defaultManager]; NSError *error = nil; BOOL result = [fm removeItemAtPath:path error:&error]; if (!result) { NSLog(“The error was: %@“, [error localizedDescription]); }

Slide 14

Slide 14 text

!

Slide 15

Slide 15 text

Stockholm)Syndrome?

Slide 16

Slide 16 text

Objec&ve(C*has*some*really*great*features.

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

2014

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

Swi$%is%different.

Slide 21

Slide 21 text

Swi$%is • clean'&'concise • memory'managed • safe • func3onal'(?)

Slide 22

Slide 22 text

Why$do$we$need$a$safe$language?

Slide 23

Slide 23 text

remember%goto%fail?

Slide 24

Slide 24 text

no?

Slide 25

Slide 25 text

hashOut.data = hashes + SSL_MD5_DIGEST_LEN; hashOut.length = SSL_SHA1_DIGEST_LEN; if ((err = SSLFreeBuffer(&hashCtx)) != 0) goto fail; if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail; err = sslRawVerify(...); . . .

Slide 26

Slide 26 text

hashOut.data = hashes + SSL_MD5_DIGEST_LEN; hashOut.length = SSL_SHA1_DIGEST_LEN; if ((err = SSLFreeBuffer(&hashCtx)) != 0) goto fail; if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; <---------- if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail; err = sslRawVerify(...); . . .

Slide 27

Slide 27 text

Hidden&backdoor&to root$in$OS$X !! !!!h#ps:/ /truesecdev.wordpress.com/2015/04/09/hidden;backdoor;api;to;root;privileges;in;apple;os;x/

Slide 28

Slide 28 text

! !!h#ps:/ /twi#er.com/tlrobinson/status/586202234582507520

Slide 29

Slide 29 text

“Swi%&Sucks”

Slide 30

Slide 30 text

“What&the&hell&were&they&thinking?”

Slide 31

Slide 31 text

"Let’s'implement'our'own'open1 source'Swi4"

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Swi$%is%unique

Slide 34

Slide 34 text

Idioma'c)Swi,

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

We#are#s'll#learning#what#idioma'c# Swi4#is.

Slide 37

Slide 37 text

So#let’s#take#a#look#at#some#cases#from#a#Swi1# viewpoint.

Slide 38

Slide 38 text

Lazy%Proper+es%with%Closures

Slide 39

Slide 39 text

func viewDidLoad() { super.viewDidLoad() let config = NSURLSessionConfiguration.defaultSessionConfiguration() session = NSURLSession( configuration: config, delegate: self, delegateQueue: nil) navigationItem.leftBarButtonItem = UIBarButtonItem( barButtonSystemItem: .Bookmarks, target: self, action: "bookmarks:") navigationItem.rightBarButtonItem = UIBarButtonItem( barButtonSystemItem: .Add, target: self, action: "add:") ... }

Slide 40

Slide 40 text

@interface MyViewController () @property (nonatomic, strong) NSURLSessionConfiguration *configuration; @end - (NSURLSessionConfiguration *)configuration { if (_configuration == nil) { _configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; } return _configuration; }

Slide 41

Slide 41 text

lazy var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()

Slide 42

Slide 42 text

lazy var configuration = NSURLSessionConfiguration.defaultSessionConfiguration() lazy var session = ...

Slide 43

Slide 43 text

lazy var configuration = NSURLSessionConfiguration.defaultSessionConfiguration() lazy var session: NSURLSession = { }()

Slide 44

Slide 44 text

lazy var configuration = NSURLSessionConfiguration.defaultSessionConfiguration() lazy var session: NSURLSession = { return NSURLSession(configuration: self.configuration, delegate: self, delegateQueue: nil) }()

Slide 45

Slide 45 text

lazy var configuration = NSURLSessionConfiguration.defaultSessionConfiguration() lazy var session: NSURLSession = { return NSURLSession(configuration: self.configuration, delegate: self, delegateQueue: nil) }() lazy var leftBarButtonItem: UIBarButtonItem = { return UIBarButtonItem( barButtonSystemItem: .Bookmarks, target: self, action: "bookmarks:") }() lazy var rightBarButtonItem: UIBarButtonItem = { return UIBarButtonItem( barButtonSystemItem: .Add, target: self, action: "add:") }()

Slide 46

Slide 46 text

func viewDidLoad() { super.viewDidLoad() let config = NSURLSessionConfiguration.defaultSessionConfiguration() session = NSURLSession( configuration: config, delegate: self, delegateQueue: nil) navigationItem.leftBarButtonItem = UIBarButtonItem( barButtonSystemItem: .Bookmarks, target: self, action: "bookmarks:") navigationItem.rightBarButtonItem = UIBarButtonItem( barButtonSystemItem: .Add, target: self, action: "add:") ... }

Slide 47

Slide 47 text

func viewDidLoad() { super.viewDidLoad() navigationItem.leftBarButtonItem = leftBarButtonItem navigationItem.rightBarButtonItem = rightBarButtonItem }

Slide 48

Slide 48 text

Returning)errors

Slide 49

Slide 49 text

var error: NSError? = nil let object = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error )

Slide 50

Slide 50 text

class func JSONObjectWithData(data: NSData, options: NSJSONReadingOptions, error: NSErrorPointer) -> AnyObject

Slide 51

Slide 51 text

func JSONObjectWithData( data: NSData, options: NSJSONReadingOptions = nil, ) -> (AnyObject?, NSError?)

Slide 52

Slide 52 text

let result = JSONObjectWithData(data) result.0 // object? result.1 // error?

Slide 53

Slide 53 text

let (object, error) = JSONObjectWithData(data) if let someObject = object { // can work with someObject } else { // error }

Slide 54

Slide 54 text

func JSONObjectWithData( data: NSData, options: NSJSONReadingOptions = nil, ) -> (obj: AnyObject?, error: NSError?)

Slide 55

Slide 55 text

let result = JSONObjectWithData(data) result.obj // object? result.error // error?

Slide 56

Slide 56 text

Some%mes'if let'sucks

Slide 57

Slide 57 text

Swi$%Pa(ern%Matching

Slide 58

Slide 58 text

switch(result) { case (.Some(let x), nil): println("x's type is AnyObject") case (nil, .Some(let e)): println("e's type is NSError") default: }

Slide 59

Slide 59 text

A"more"general"solu-on

Slide 60

Slide 60 text

enum Result { case Value(T) case Error(NSError) }

Slide 61

Slide 61 text

func JSONObjectWithData( data: NSData, options: NSJSONReadingOptions = nil ) -> Result

Slide 62

Slide 62 text

func JSONObjectWithData( data: NSData, options: NSJSONReadingOptions = nil ) -> Result { .... if let error = parserError { return .Error(error) } else { return .Value(parsedObject) } }

Slide 63

Slide 63 text

let result = JSONObjectWithData(data) switch(result) { case .Value(let obj): println("we parsed the object: \(obj)") case .Error(let error): println("error parsing json: \(error)") }

Slide 64

Slide 64 text

(Side&Note:&Boxing¤tly&required) Hopefully)Apple)will)fix)this)soon,)but)currently)you)need)to)box)the) T)value)for)this)to)work: class Box { var unbox: T init(_ value: T) { unbox = value } }

Slide 65

Slide 65 text

enum Result { case Value(Box) case Error(NSError) } switch result { case .Value(let box): let val = box.unbox ... }

Slide 66

Slide 66 text

More%on%Result%later...

Slide 67

Slide 67 text

Map$/$Reduce

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

struct Item { let name: String let price: Double let taxable: Bool }

Slide 70

Slide 70 text

Given&a&Shopping&cart&full&of&items... let shoppingCart = [ Item(name: "Apples", price: 0.67, taxable: false), Item(name: "Bananas", price: 1.87, taxable: false), Item(name: "Beer", price: 6.99, taxable: true), Item(name: "Candy", price: 4.00, taxable: true), Item(name: "Ice Cream", price: 6.00, taxable: true) ]

Slide 71

Slide 71 text

Compute(the(amount(of(tax(you( have(to(pay...

Slide 72

Slide 72 text

let TaxRate = 0.0825

Slide 73

Slide 73 text

let TaxRate = 0.0825 var tax = 0.0

Slide 74

Slide 74 text

let TaxRate = 0.0825 var tax = 0.0 for item in shoppingCart { } println(tax)

Slide 75

Slide 75 text

let TaxRate = 0.0825 var tax = 0.0 for item in shoppingCart { if item.taxable { } } println(tax)

Slide 76

Slide 76 text

let TaxRate = 0.0825 var tax = 0.0 for item in shoppingCart { if item.taxable { tax += item.price * TaxRate } } println(tax)

Slide 77

Slide 77 text

How$can$we$express$this$in$terms$of$ map,$filter,$and$reduce?

Slide 78

Slide 78 text

map

Slide 79

Slide 79 text

func map( source: C, transform: (C.Generator.Element) -> T) -> [T]

Slide 80

Slide 80 text

func map( source: S, transform: (S.Generator.Element) -> T) -> [T]

Slide 81

Slide 81 text

let items = [1, 2, 3] map(items, { (item: Int) -> Int in return item * 2 })

Slide 82

Slide 82 text

let items = [1, 2, 3] map(items, { (item) -> Int in return item * 2 })

Slide 83

Slide 83 text

let items = [1, 2, 3] map(items, { item in return item * 2 })

Slide 84

Slide 84 text

map(items, { return $0 * 2 })

Slide 85

Slide 85 text

map(items, { $0 * 2 })

Slide 86

Slide 86 text

map(items) { $0 * 2 }

Slide 87

Slide 87 text

[1,2,3].map { $0 * 2 }

Slide 88

Slide 88 text

[1,2,3].map { $0 * 2 } // => [2, 4, 6]

Slide 89

Slide 89 text

filter

Slide 90

Slide 90 text

func filter( source: S, includeElement: (S.Generator.Element) -> Bool) -> [S.Generator.Element]

Slide 91

Slide 91 text

[1,2,3].filter { $0 % 2 == 0 }

Slide 92

Slide 92 text

[1,2,3].filter { $0 % 2 == 0 } // => [2]

Slide 93

Slide 93 text

reduce

Slide 94

Slide 94 text

func reduce( sequence: S, initial: U, combine: @noescape (U, S.Generator.Element) -> U) -> U

Slide 95

Slide 95 text

[1,2,3].reduce(0) { (sum, n) in return sum + n }

Slide 96

Slide 96 text

All#set?

Slide 97

Slide 97 text

First&get&the&taxable&items let taxable = shoppingCart.filter { $0.taxable }

Slide 98

Slide 98 text

Map$items$to$their$prices let taxable = shoppingCart.filter { $0.taxable } let taxableAmounts = taxable.map { $0.price }

Slide 99

Slide 99 text

Reduce&to&a&single&value&(the&amount&of&tax) let taxable = shoppingCart.filter { $0.taxable } let taxableAmounts = taxable.map { $0.price } let tax = taxableAmounts.reduce(0) { (tax, itemPrice) in return tax + (itemPrice * TaxRate) }

Slide 100

Slide 100 text

Can$simplify$the$reduce$block... let taxable = shoppingCart.filter { $0.taxable } let taxableAmounts = taxable.map { $0.price } let itemTaxes = taxable.map { $0 * TaxRate } let tax = itemTaxes.reduce(0) { (tax, itemTax) in return tax + (itemTax) }

Slide 101

Slide 101 text

...into&an&exis+ng&func+on

Slide 102

Slide 102 text

func +(lhs: Int, rhs: Int) -> Int { return lhs + rhs }

Slide 103

Slide 103 text

Look$at$the$Shape$of$the$func/on... (T,T) -> U

Slide 104

Slide 104 text

Look$at$the$Shape$of$the$func/on... !-> T

Slide 105

Slide 105 text

(T,T)-> T

Slide 106

Slide 106 text

(U,T)-> U

Slide 107

Slide 107 text

Can$just$use$the$+$func-on... let taxable = shoppingCart.filter { $0.taxable } let taxableAmounts = taxable.map { $0.price } let itemTaxes = taxable.map { $0 * TaxRate } let tax = itemTaxes.reduce(0, combine: +)

Slide 108

Slide 108 text

..."and"chain"them"together... let tax = shoppingCart .filter { $0.taxable } .map { $0.price } .map { $0 * TaxRate } .reduce(0, combine: +) println(tax) // 1.40

Slide 109

Slide 109 text

Func%ons (no$interim$state,$no$loops,$no$condi1onals)

Slide 110

Slide 110 text

func taxFunction(rate: Double)

Slide 111

Slide 111 text

func taxFunction(rate: Double) -> ([Item]) -> Double {

Slide 112

Slide 112 text

func taxFunction(rate: Double) -> ([Item]) -> Double { return { (items) in return items .filter { $0.taxable } .map { $0.price } .map { $0 * rate } .reduce(0, combine: +) } }

Slide 113

Slide 113 text

let texasTax = taxFunction(0.0825) let tax = texasTax(items)

Slide 114

Slide 114 text

Flat%Map

Slide 115

Slide 115 text

We#know#what#map#is,#what#is#fla1en? flatten([[5, 6], [4], [7, 8]]) -> [5,6,4,7,8]

Slide 116

Slide 116 text

it#is#o&en#handy#to#fla.en#before# mapping

Slide 117

Slide 117 text

(flat,&map)

Slide 118

Slide 118 text

struct Person { var name: String var emails: [String] }

Slide 119

Slide 119 text

"Give&me&a&list&of&all&email& addresses"

Slide 120

Slide 120 text

people.map { $0.emails } ???

Slide 121

Slide 121 text

There%is%no%fla,en%func0on,%but%we%could% write%one... func flatten(array: [[T]) -> [T] { var result = [T]() for item in array { for subItem in item { result.append(subItem) } } return result }

Slide 122

Slide 122 text

...ore%more%succinctly,%with%reduce: func flatten(array: [[T]) -> [T] { return array.reduce([], combine: +) }

Slide 123

Slide 123 text

Yay!%Swi)%1.2%has%a%flatMap% func3on%:)

Slide 124

Slide 124 text

[[1, 2], [3], [4, 5]].flatMap { $0 } // -> [1, 2, 3, 4, 5]

Slide 125

Slide 125 text

people.flatMap { $0.emails }

Slide 126

Slide 126 text

flatMap&for&Result&?

Slide 127

Slide 127 text

enum Result { case Value(Box) case Error(NSError) func flatMap(next: T -> Result) -> Result { switch self { case .Value(let box): let val = box.unbox return next(val) case .Error(let err): return .Error(err) } } }

Slide 128

Slide 128 text

func getValue() -> Result func convertToFloat(i: Int) -> Result func squareRoot(x: Float) -> Result

Slide 129

Slide 129 text

getValue().flatMap(convertToFloat).flatMap(squareRoot)

Slide 130

Slide 130 text

Dealing(with(Index(Paths

Slide 131

Slide 131 text

Remember&sta*c&table&views&before& Storyboards?

Slide 132

Slide 132 text

func tableView(tableView: UITableView, cellForRowAtIndexPath: NSIndexPath) -> UITableViewCell { if indexPath.section == 0 { if indexPath.row == 0 { // } else { // ... } } else if indexPath.section == numberOfSectionsInTableView(tableView) - 1 { // ... } else { // ... } }

Slide 133

Slide 133 text

func tableView(tableView: UITableView, cellForRowAtIndexPath: NSIndexPath) -> UITableViewCell { switch (indexPath) { case (0, 0): ... case (0, let row): ... case (let section, let row) where isLastSection(section): ... case (let section, let row): ... } }

Slide 134

Slide 134 text

Enums&for&API&Endpoints

Slide 135

Slide 135 text

Consider)an)API)with)some)paths: • /notifications • /users/:username • /catgories/:category_id/products/:product_id

Slide 136

Slide 136 text

enum ApiEndpoints { case Notifications case UserProfile(String) case ProductDetail(Int, Int) }

Slide 137

Slide 137 text

enum ApiEndpoints { case Notifications case UserProfile(String) case ProductDetail(Int, Int) var path: String { switch(self) { case .Notifications: return "/notifications" case .UserProfile(let username): return "/users/\(username.stringByAddingPercentEscapes...)" case .ProductDetail(let categoryId, let productId): return "/categories/\(categoryId)/products/\(productId)" } } }

Slide 138

Slide 138 text

ApiClient.request(.UserProfile("subdigital")) { ... }

Slide 139

Slide 139 text

Swi$%is%s'll%new

Slide 140

Slide 140 text

!

Slide 141

Slide 141 text

"When&we&learn&a&new&programming& language,&we&may&need&[to]&discard& what&we&thought&it&should&be,&and& learn&what&it&will&be." —"a"Swi'"student

Slide 142

Slide 142 text

thanks! @subdigital+•+@nsscreencast