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

気遣いの iOS プログラミング

Yuka Ezura
September 01, 2018

気遣いの iOS プログラミング

iosdc2018
Speaker deck だとリンクがクリックできないので、ここに貼ります!

## associated value の章
バグが見つかり一時的に禁止: https://github.com/apple/swift/commit/bf71ec85995b1a7fc26c811eae4a7a99504654d5

解決済み: https://github.com/apple/swift/commit/f5f715f8ffd6c6deed0637ff0013890947feb506

## map / flatMap
https://github.com/apple/swift/blob/c66e136c18fc4146c7ef3eb52f5e534245b34a1c/stdlib/public/core/Optional.swift#L166

Yuka Ezura

September 01, 2018
Tweet

More Decks by Yuka Ezura

Other Decks in Programming

Transcript

  1. • ezura • ׆ಈ • try!Swift Tokyo • iOSDC •

    mockmock radio • αʔΫϧ: Swift প • Work at LINE !2
  2. Agenda • ෳ਺ͷྻڍࢠͷ associated value ΛಉҰࢹ͢Δ • Optional ΁ͷଶ౓ •

    Closure Ͱ஫໨͢Δର৅Λม͑Δ • ॳظઃఆͷ 3 ͭͷํ๏ !5
  3. 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
  4. 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
  5. 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
  6. case .comic(_, let content), .novel(let content): return content case .comic(_,

    let content): return content case .novel(let content): return content !10 ҟͳΔ΋ͷͱͯ͠ѻ͏ ಉҰࢹ͢Δ
  7. 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
  8. ·ͱΊ !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 Ͱ࠶ղې) ಉ͡ม਺໊, ܕ ϥϕϧͷ༗ແ΍໊લ͸ແؔ܎
  9. if let book = book { … } guard let

    book = book else { … } book?.method book!.method book ?? defaultValue ... !14
  10. !17 if let book = book, case .comic(let tag) =

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

    { ... } if case .comic(let tag)? = book { ... } !18
  12. guard let item = item else { return nil }

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

    return OtherModel(item) !20 return item?.asOtherModel() `OtherModel` ͷ function `Item` ͷ function
  14. 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
  15. 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<OtherModel>> Optional<Item> Optional<OtherModel> Optional<OtherModel> Optional<OtherModel> https://github.com/apple/swift/blob/c66e136c18fc4146c7ef3eb52f5e534245b34a1c/stdlib/public/core/Optional.swift#L166
  16. 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 Ͱ෼͔Γ΍͍͢ • ෳࡶͳঢ়ଶͰ΋៉ྷʹ·ͱΊΒΕΔ • ୯७ͳॲཧΛ؆ܿʹදݱՄೳ • ෳࡶͳঢ়گΛ·ͱΊΑ͏ͱ͢Δͱ
 ಡΈʹ͘͘ͳΔ
  17. ·ͱΊ !24 if let book = book { … }

    guard let book = book else { … } book?.method book!.method book ?? defaultValue case .comic? = book { … } book.map { … } / book.flatMap { … }
  18. if /* condition */ { titleLabel.text = "All good!" }

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

    good!" } else if /* condition */ { return "Warning" } else { return nil } }() !27 titleLabel ʹදࣔ͢ΔςΩετΛઃఆ͢Δ
 ඞͣԿ͔ઃఆ͢Δ (ྫ֎ൃੜআ͘) ৚݅෼ذͯ͠Δ
  20. 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 ΁ͷઃఆΛڧௐ • ඞͣԿΒ͔ͷ஋͕ઃఆ͞ΕΔ͜ͱͷอূ είʔϓΛ۠੾ΕΔ
  21. 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
  22. 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
  23. (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
  24. (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? ؔ࿈ੑ͕ऑ͍
  25. (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 ஫: ؔ࿈ͷڧ͍΋ͷಉ࢜ʹ͢Δ
  26. let confirmButton = UIButton() confirmButton.backgroundColor = .white confirmButton.setImage(⬛, for: .normal)

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

    confirmButton.imageView?.clipsToBounds = false confirmButton.imageView?.contentMode = .center !36
  28. 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
  29. let confirmButton = UIButton(); do { confirmButton.backgroundColor = .white confirmButton.setImage(⬛,

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

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

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

    for: .normal) confirmButton.imageView?.clipsToBounds = false confirmButton.imageView?.contentMode = .center } ํ๏ 2 !41 จͷ۠੾ΕΛ໌ࣔ είʔϓΛ۠੾ΔͨΊͷ `do` • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ϒϩοΫ಺ͰͷԾͷΠϯελϯε͕ෆཁ • ஋ܕͷ৔߹ɺ`var` ࢦఆ͕ඞཁ • ϒϩοΫͷ్தͰൈ͚͍ͨ৔߹ɺ
 Մಡੑ͕ѱ͘ͳΔ
  33. 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 ͕ෳࡶͳ৔߹ɺݟ௨͕͠ѱ͍
  34. @discardableResult func with<T>(_ 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 ஋ܕ΋αϙʔτ
  35. 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
  36. 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 Ͱ࠶ղې) ಉ͡ม਺໊, ܕ ϥϕϧͷ༗ແ΍໊લ͸ແؔ܎
  37. Optional ΁ͷଶ౓ !48 if let book = book { …

    } guard let book = book else { … } book?.method book!.method book ?? defaultValue case .comic? = book { … } book.map { … } / book.flatMap { … }
  38. 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 Ͱ஫໨͢Δର৅Λม͑Δ
  39. 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