Slide 1

Slide 1 text

ؾݣ͍ͷ iOS ϓϩάϥϛϯά 2018/9/1 #iosdc #b ezura

Slide 2

Slide 2 text

• ezura • ׆ಈ • try!Swift Tokyo • iOSDC • mockmock radio • αʔΫϧ: Swift প • Work at LINE !2

Slide 3

Slide 3 text

ීஈ࢖͍ͷ
 Good practices !3

Slide 4

Slide 4 text

໨త ❌ “͜͏͍͏৔߹͸͜Ε͕ϕετ” ͷٞ࿦ ⭕ ΑΓྑ͍ํ๏Λબ୒͢ΔҾ͖ग़͠Λ૿΍͢ !4

Slide 5

Slide 5 text

Agenda • ෳ਺ͷྻڍࢠͷ associated value ΛಉҰࢹ͢Δ • Optional ΁ͷଶ౓ • Closure Ͱ஫໨͢Δର৅Λม͑Δ • ॳظઃఆͷ 3 ͭͷํ๏ !5

Slide 6

Slide 6 text

ෳ਺ͷྻڍࢠͷ associated value ΛಉҰࢹ͢Δ !6

Slide 7

Slide 7 text

enum Book { case comic(tag: Tag, content: Content) case novel(content: Content) var content: Content { switch self { case .comic(_, let content): return content case .novel(let content): return content } } } !7 associated value

Slide 8

Slide 8 text

enum Book { case comic(tag: Tag, content: Content) case novel(content: Content) var content: Content { switch self { case .comic(_, let content): return content case .novel(let content): return content } } } !8 associated value

Slide 9

Slide 9 text

enum Book { case comic(tag: Tag, content: Content) case novel(content: Content) var content: Content { switch self { case .comic(_, let content), .novel(let content): return content } } } !9 associated value

Slide 10

Slide 10 text

case .comic(_, let content), .novel(let content): return content case .comic(_, let content): return content case .novel(let content): return content !10 ҟͳΔ΋ͷͱͯ͠ѻ͏ ಉҰࢹ͢Δ

Slide 11

Slide 11 text

enum APIError { case networkError(NetworkError) case authError(AuthError) } … switch apiError { case .networkError(let error as Error), .authError(let error as Error): // do something // use `error` as `Error` // do something } όά͕ݟ͔ͭΓҰ࣌తʹېࢭ: https://github.com/apple/swift/commit/bf71ec85995b1a7fc26c811eae4a7a99504654d5
 ղܾࡁΈ: https://github.com/apple/swift/commit/f5f715f8ffd6c6deed0637ff0013890947feb506 ໌ࣔతͳ Cast Ͱ࢖༻Մೳʹ
 (Xcode10 Ͱ෮׆) !11

Slide 12

Slide 12 text

·ͱΊ !12 enum Enum { case simple(TypeA) case complex(TypeA, TypeB) case empty } ... switch e { case .simple(let ): // do something // use `` case .complex(let , _): // do something // use `` case .empty: // do something } switch e { case .simple(let ), .complex(let , _): // do something // use `` case .empty: // do something } • ஋ΛಉҰࢹ͢Δʁ͠ͳ͍ʁ • ܕ͕ҟͳΔͱ͖͸໌ࣔతʹܕΛࢦఆ͢Δ 
 (Xcode10 Ͱ࠶ղې) ಉ͡ม਺໊, ܕ ϥϕϧͷ༗ແ΍໊લ͸ແؔ܎

Slide 13

Slide 13 text

Handling Optional Value !13

Slide 14

Slide 14 text

if let book = book { … } guard let book = book else { … } book?.method book!.method book ?? defaultValue ... !14

Slide 15

Slide 15 text

if let book = book, case .comic(let tag) = book { ... } !15 Optional

Slide 16

Slide 16 text

if case .comic(let tag)? = book { ... } !16

Slide 17

Slide 17 text

!17 if let book = book, case .comic(let tag) = book { ... } if case .comic(let tag)? = book { ... }

Slide 18

Slide 18 text

if let book = book, case .comic(let tag) = book { ... } if case .comic(let tag)? = book { ... } !18

Slide 19

Slide 19 text

guard let item = item else { return nil } return OtherModel(item) !19 ඇ Optional ΛҾ਺ʹͱΔؔ਺/initializer Optional

Slide 20

Slide 20 text

guard let item = item else { return nil } return OtherModel(item) !20 return item?.asOtherModel() `OtherModel` ͷ function `Item` ͷ function

Slide 21

Slide 21 text

guard let item = item else { return nil } return OtherModel(item) return item.map { OtherModel($0) }
 return item.flatMap { OtherModel($0) }
 //return item.map(OtherModel.init) !21 Value map / flatMap

Slide 22

Slide 22 text

guard let item = item else { return nil } return OtherModel(item) return item.map { OtherModel($0) }
 return item.flatMap { OtherModel($0) }
 Value map / flatMap Optional> Optional Optional Optional Optional https://github.com/apple/swift/blob/c66e136c18fc4146c7ef3eb52f5e534245b34a1c/stdlib/public/core/Optional.swift#L166

Slide 23

Slide 23 text

guard let item = item, let obj = obj else { return nil } return OtherModel(arg1: item, arg2: obj) return item.map { OtherModel($0) }
 return item.flatMap { OtherModel($0) }
 //return item.map(OtherModel.init) !23 • ໌ࣔతͳ unwrap Ͱ෼͔Γ΍͍͢ • ෳࡶͳঢ়ଶͰ΋៉ྷʹ·ͱΊΒΕΔ • ୯७ͳॲཧΛ؆ܿʹදݱՄೳ • ෳࡶͳঢ়گΛ·ͱΊΑ͏ͱ͢Δͱ
 ಡΈʹ͘͘ͳΔ

Slide 24

Slide 24 text

·ͱΊ !24 if let book = book { … } guard let book = book else { … } book?.method book!.method book ?? defaultValue case .comic? = book { … } book.map { … } / book.flatMap { … }

Slide 25

Slide 25 text

Closure ʹΑͬͯ
 ஫໨͢Δର৅Λม͑Δ !25

Slide 26

Slide 26 text

if /* condition */ { titleLabel.text = "All good!" } else if /* condition */ { titleLabel.text = "Warning" } else { titleLabel.text = nil } !26 ৚݅෼ذͯ͠Δ titleLabel ͷ text Λઃఆͯ͠Δ ͜͜΋ titleLabel.text ͷઃఆ શ෦ͦ͏ͩ titleLabel ʹදࣔ͢ΔςΩετΛ৚݅Ԡͯ͡ઃఆ͢Δ
 ඞͣԿ͔ઃఆ͢Δ

Slide 27

Slide 27 text

titleLabel.text = { if /* condition */ { return "All good!" } else if /* condition */ { return "Warning" } else { return nil } }() !27 titleLabel ʹදࣔ͢ΔςΩετΛઃఆ͢Δ
 ඞͣԿ͔ઃఆ͢Δ (ྫ֎ൃੜআ͘) ৚݅෼ذͯ͠Δ

Slide 28

Slide 28 text

if true /* condition */ { titleLabel.text = "All good!" } else if true /* condition */ { titleLabel.text = "Warning" } else { titleLabel.text = nil } titleLabel.text = { if true /* condition */ { return "All good!" } else if true /* condition */ { return "Warning" } else { return nil } }() !28 ৚݅ʹԠͯ͡Կ͔͢Δ͜ͱΛڧௐ • titleLabel.text ΁ͷઃఆΛڧௐ • ඞͣԿΒ͔ͷ஋͕ઃఆ͞ΕΔ͜ͱͷอূ είʔϓΛ۠੾ΕΔ

Slide 29

Slide 29 text

if /* condition */ { titleLabel.text = "All good!" subtitleLabel.text = "You can use all service." } else if /* condition */ { titleLabel.text = "Warning" subtitleLabel.text = "Please check your acount." } else { titleLabel.text = nil subtitleLabel.text = nil } !29

Slide 30

Slide 30 text

titleLabel.text = { if /* condition */ { return "All good!" } else if /* condition */ { return "Warning" } else { return nil } }() subtitleLabel.text = { if /* condition */ { return "You can use all service." } else if /* condition */ { return "Please check your acount." } else { return nil } }() !30

Slide 31

Slide 31 text

(titleLabel.text, subtitleLabel.text) = { if /* condition */ { return (title: "All good!", subtitle: "You can use all service.") } else if /* condition */ { return (title: "Warning", subtitle: "Please check your acount.") } else { return (title: nil, subtitle: nil) } }() !31

Slide 32

Slide 32 text

(titleLabel.text, x) = { if /* condition */ { return (title: "Good!", x: 0) } else if /* condition */ { return (title: "Better", x: maxRect.minX) } else { return (title: nil, x: maxRect.maxX) } }() !32 titile? x? ؔ࿈ੑ͕ऑ͍

Slide 33

Slide 33 text

(titleLabel.text, subtitleLabel.text) = { if /* condition */ { return (title: "All good!", subtitle: "You can use all service.") } else if /* condition */ { return (title: "Warning", subtitle: "Please check your acount.") } else { return (title: nil, subtitle: nil) } }() !33 ஫: ؔ࿈ͷڧ͍΋ͷಉ࢜ʹ͢Δ

Slide 34

Slide 34 text

ॳظԽॲཧ !34

Slide 35

Slide 35 text

let confirmButton = UIButton() confirmButton.backgroundColor = .white confirmButton.setImage(⬛, for: .normal) confirmButton.imageView?.clipsToBounds = false confirmButton.imageView?.contentMode = .center !35

Slide 36

Slide 36 text

let confirmButton = UIButton() confirmButton.backgroundColor = .white confirmButton.setImage(⬛, for: .normal) confirmButton.imageView?.clipsToBounds = false confirmButton.imageView?.contentMode = .center !36

Slide 37

Slide 37 text

let confirmButton: UIButton = { let button = UIButton() button.backgroundColor = .white button.setImage(⬛, for: .normal) button.imageView?.clipsToBounds = false button.imageView?.contentMode = .center return button }() ํ๏ 1 !37 • ൚༻త͔ͭҰൠత • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ઃఆର৅ͷม਺Λ `let` ʹͰ͖Δ ΠϯελϯεΛ࡞Δ ׬੒ͨ͠ΠϯελϯεΛฦ͢ ஋ܕͷ৔߹Ͱ΋ `let` Ͱ OK

Slide 38

Slide 38 text

let confirmButton = UIButton(); do { confirmButton.backgroundColor = .white confirmButton.setImage(⬛, for: .normal) confirmButton.imageView?.clipsToBounds = false confirmButton.imageView?.contentMode = .center } ํ๏ 2 !38 จͷ۠੾ΕΛ໌ࣔ είʔϓΛ۠੾Δ `do` • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ϒϩοΫ಺ͰͷԾͷΠϯελϯε͕ෆཁ • ஋ܕͷ৔߹ɺ`var` ࢦఆ͕ඞਢ • ϒϩοΫͷ్தͰൈ͚͍ͨ৔߹ɺ
 Մಡੑ͕ѱ͘ͳΔ

Slide 39

Slide 39 text

var text = "value"; do { text.append(suffix) ... } ํ๏ 2 !39 ஋ܕͷ৔߹ɺ
 มߋՃ͑Δ৔߹ʹ mutable ੑඞਢ • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ϒϩοΫ಺ͰͷԾͷΠϯελϯε͕ෆཁ • ஋ܕͷ৔߹ɺ`var` ࢦఆ͕ඞཁ • ϒϩοΫͷ్தͰൈ͚͍ͨ৔߹ɺ
 Մಡੑ͕ѱ͘ͳΔ

Slide 40

Slide 40 text

let confirmButton = UIButton(); ready: do { confirmButton.backgroundColor = .white guard true /* condition */ else { break ready } ... } ํ๏ 2 !40 • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ϒϩοΫ಺ͰͷԾͷΠϯελϯε͕ෆཁ • ஋ܕͷ৔߹ɺ`var` ࢦఆ͕ඞཁ • ϒϩοΫͷ్தͰൈ͚͍ͨ৔߹ɺ
 Մಡੑ͕ѱ͘ͳΔ

Slide 41

Slide 41 text

let confirmButton = UIButton(); do { confirmButton.backgroundColor = .white confirmButton.setImage(⬛, for: .normal) confirmButton.imageView?.clipsToBounds = false confirmButton.imageView?.contentMode = .center } ํ๏ 2 !41 จͷ۠੾ΕΛ໌ࣔ είʔϓΛ۠੾ΔͨΊͷ `do` • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ϒϩοΫ಺ͰͷԾͷΠϯελϯε͕ෆཁ • ஋ܕͷ৔߹ɺ`var` ࢦఆ͕ඞཁ • ϒϩοΫͷ్தͰൈ͚͍ͨ৔߹ɺ
 Մಡੑ͕ѱ͘ͳΔ

Slide 42

Slide 42 text

let confirmButton = with(UIButton()) { button in button.backgroundColor = .white button.setImage(⬛, for: .normal) button.imageView?.clipsToBounds = false button.imageView?.contentMode = .center } ํ๏ 3 !42 • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ઃఆର৅ͷม਺Λ࠷ऴతʹ `let` ʹͰ͖Δ • Closure ಺ͰͷԾͷΠϯελϯεએݴ͕ෆཁ • initializer ͕ෳࡶͳ৔߹ɺݟ௨͕͠ѱ͍

Slide 43

Slide 43 text

@discardableResult func with(_ item: T, update: (inout T) throws -> Void) rethrows -> T { var this = item try update(&this) return this } ํ๏ 3 !43 ग़య: 
 Swift Style, Second Edition by Erica Sadun https://pragprog.com/book/esswift2/swift-style-second-edition ஋ܕ΋αϙʔτ

Slide 44

Slide 44 text

let confirmButton = UIButton(); do { confirmButton.backgroundColor = .white } let confirmButton: UIButton = { let button = UIButton() button.backgroundColor = .white return button }() let confirmButton = with(UIButton()) { button in button.backgroundColor = .white } Initialize !44 Immediately Invoked Closures do-block Custom function

Slide 45

Slide 45 text

·ͱΊ !45

Slide 46

Slide 46 text

ීஈ࢖͍ͷ
 Good practices ΑΓྑ͍ํ๏Λબ୒͢ΔͨΊͷҾ͖ग़͠ !46

Slide 47

Slide 47 text

Handling associated value !47 enum Enum { case simple(TypeA) case complex(TypeA, TypeB) case empty } ... switch e { case .simple(let ): // do something // use `` case .complex(let , _): // do something // use `` case .empty: // do something } switch e { case .simple(let ), .complex(let , _): // do something // use `` case .empty: // do something } • ஋ΛಉҰࢹ͢Δʁ͠ͳ͍ʁ • ܕ͕ҟͳΔͱ͖͸໌ࣔతʹܕΛࢦఆ͢Δ 
 (Xcode10 Ͱ࠶ղې) ಉ͡ม਺໊, ܕ ϥϕϧͷ༗ແ΍໊લ͸ແؔ܎

Slide 48

Slide 48 text

Optional ΁ͷଶ౓ !48 if let book = book { … } guard let book = book else { … } book?.method book!.method book ?? defaultValue case .comic? = book { … } book.map { … } / book.flatMap { … }

Slide 49

Slide 49 text

if true /* condition */ { titleLabel.text = "All good!" } else if true /* condition */ { titleLabel.text = "Warning" } else { titleLabel.text = nil } titleLabel.text = { if true /* condition */ { return "All good!" } else if true /* condition */ { return "Warning" } else { return nil } }() !49 ৚݅ʹԠͯ͡Կ͔͢Δ͜ͱΛڧௐ • titleLabel.text ΁ͷઃఆΛڧௐ • ඞͣԿΒ͔ͷ஋͕ઃఆ͞ΕΔ͜ͱͷอূ είʔϓΛ۠੾ΕΔ Closure Ͱ஫໨͢Δର৅Λม͑Δ

Slide 50

Slide 50 text

let confirmButton = UIButton(); do { confirmButton.backgroundColor = .white } let confirmButton: UIButton = { let button = UIButton() button.backgroundColor = .white return button }() let confirmButton = with(UIButton()) { button in button.backgroundColor = .white } Initialize !50 Immediately Invoked Closures do-block Custom function

Slide 51

Slide 51 text

Capture list Autolayout Interface builder tips ૉ੖Β͖͠ enum ඞम protocol ศརίϚϯυ Swift4.2 attributes !51

Slide 52

Slide 52 text

Thank you for listening !52