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

6a55a7fb19c1fa78e86ddca7a69db088?s=47 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

6a55a7fb19c1fa78e86ddca7a69db088?s=128

Yuka Ezura

September 01, 2018
Tweet

Transcript

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

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

    mockmock radio • αʔΫϧ: Swift প • Work at LINE !2
  3. ීஈ࢖͍ͷ
 Good practices !3

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

  5. Agenda • ෳ਺ͷྻڍࢠͷ associated value ΛಉҰࢹ͢Δ • Optional ΁ͷଶ౓ •

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

  7. 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
  8. 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
  9. 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
  10. case .comic(_, let content), .novel(let content): return content case .comic(_,

    let content): return content case .novel(let content): return content !10 ҟͳΔ΋ͷͱͯ͠ѻ͏ ಉҰࢹ͢Δ
  11. 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
  12. ·ͱΊ !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 Ͱ࠶ղې) ಉ͡ม਺໊, ܕ ϥϕϧͷ༗ແ΍໊લ͸ແؔ܎
  13. Handling Optional Value !13

  14. if let book = book { … } guard let

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

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

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

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

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

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

    return OtherModel(item) !20 return item?.asOtherModel() `OtherModel` ͷ function `Item` ͷ function
  21. 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
  22. 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
  23. 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 Ͱ෼͔Γ΍͍͢ • ෳࡶͳঢ়ଶͰ΋៉ྷʹ·ͱΊΒΕΔ • ୯७ͳॲཧΛ؆ܿʹදݱՄೳ • ෳࡶͳঢ়گΛ·ͱΊΑ͏ͱ͢Δͱ
 ಡΈʹ͘͘ͳΔ
  24. ·ͱΊ !24 if let book = book { … }

    guard let book = book else { … } book?.method book!.method book ?? defaultValue case .comic? = book { … } book.map { … } / book.flatMap { … }
  25. Closure ʹΑͬͯ
 ஫໨͢Δର৅Λม͑Δ !25

  26. if /* condition */ { titleLabel.text = "All good!" }

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

    good!" } else if /* condition */ { return "Warning" } else { return nil } }() !27 titleLabel ʹදࣔ͢ΔςΩετΛઃఆ͢Δ
 ඞͣԿ͔ઃఆ͢Δ (ྫ֎ൃੜআ͘) ৚݅෼ذͯ͠Δ
  28. 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 ΁ͷઃఆΛڧௐ • ඞͣԿΒ͔ͷ஋͕ઃఆ͞ΕΔ͜ͱͷอূ είʔϓΛ۠੾ΕΔ
  29. 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
  30. 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
  31. (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
  32. (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? ؔ࿈ੑ͕ऑ͍
  33. (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 ஫: ؔ࿈ͷڧ͍΋ͷಉ࢜ʹ͢Δ
  34. ॳظԽॲཧ !34

  35. let confirmButton = UIButton() confirmButton.backgroundColor = .white confirmButton.setImage(⬛, for: .normal)

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

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

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

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

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

    for: .normal) confirmButton.imageView?.clipsToBounds = false confirmButton.imageView?.contentMode = .center } ํ๏ 2 !41 จͷ۠੾ΕΛ໌ࣔ είʔϓΛ۠੾ΔͨΊͷ `do` • είʔϓ͕۠੾ΕΔ • ॲཧΛηΫγϣϯ෼͚Ͱ͖Δ • ϒϩοΫ಺ͰͷԾͷΠϯελϯε͕ෆཁ • ஋ܕͷ৔߹ɺ`var` ࢦఆ͕ඞཁ • ϒϩοΫͷ్தͰൈ͚͍ͨ৔߹ɺ
 Մಡੑ͕ѱ͘ͳΔ
  42. 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 ͕ෳࡶͳ৔߹ɺݟ௨͕͠ѱ͍
  43. @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 ஋ܕ΋αϙʔτ
  44. 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
  45. ·ͱΊ !45

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

  47. 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 Ͱ࠶ղې) ಉ͡ม਺໊, ܕ ϥϕϧͷ༗ແ΍໊લ͸ແؔ܎
  48. Optional ΁ͷଶ౓ !48 if let book = book { …

    } guard let book = book else { … } book?.method book!.method book ?? defaultValue case .comic? = book { … } book.map { … } / book.flatMap { … }
  49. 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 Ͱ஫໨͢Δର৅Λม͑Δ
  50. 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
  51. Capture list Autolayout Interface builder tips ૉ੖Β͖͠ enum ඞम protocol

    ศརίϚϯυ Swift4.2 attributes !51
  52. Thank you for listening !52