Slide 1

Slide 1 text

J04 ΞϓϦͷ։ൃ଎౓Λ
 ʹ޲্ͤͨ͞
 σόοάϊ΢ϋ΢ Kuniwak - DeNA Co.,Ltd. 2018.09.02 iOSDC Japan 2018

Slide 2

Slide 2 text

"CPVUNF

Slide 3

Slide 3 text

,VOJXBL w ॴଐˠ w HJUIVCDPN,VOJXBL w RJJUBDPN,VOJXBL w "QQ$PEF-PWFS

Slide 4

Slide 4 text

͜ͷൃදͰ։ൃ଎౓Λ
 ͋͛ΒΕΔਓ ͸͡Ίʹ

Slide 5

Slide 5 text

్த·Ͱ͏·͍͘͘ͷʹ
 కΊ੾Γʹؒʹ߹Θͳ͍

Slide 6

Slide 6 text

కΊ੾Γ͕ഭͬͯ͘Δͱ
 ಈ࡞֬ೝΛ͖͠Εͳͯ͘
 େৎ෉ͩͱ৴͡Δ͔͠ͳ͍

Slide 7

Slide 7 text

4JNVMBUPSΆͪΆͪʹ
 ͕͔͔࣌ؒͬͯΠϥΠϥ͢Δ

Slide 8

Slide 8 text

͜Μͳ͓೰Έɺօ͞Μʹ΋͋Γ·ͤΜ͔ʁ ͜͏վળͨ͠Αʂͱ͍ͬͨମݧ͕͋Ε͹ɺ
 ͥͻUXFFU͍ͯͩ͘͠͞ʂ

Slide 9

Slide 9 text

͜ͷൃදͰ఻͍͑ͨ͜ͱ ͓೰Έͷ͋ͳͨ΁

Slide 10

Slide 10 text

΁ͷ։ൃ଎౓޲্Λࢧ͑ͨͭͷϊ΢ϋ΢ɿ --%#Λ࢖͍͜ͳ͢ σόοάͷλΠϛϯάΛมߋ௚ޙʹ͢Δ ෆ҆ۦಈͰηϧϑνΣοΫ͢Δ ಈ࡞֬ೝΛࣗಈԽ͢Δ ؒҧ͍ʹ͍͘ઃܭʹ͢Δ

Slide 11

Slide 11 text

͜ͷൃදͷޙ൒͔Β͸ɺσόοάࣗମͷϊ΢ϋ΢ͷ
 આ໌ΑΓ΋ɺߴ౓ͳσόοάΛඞཁͱ͠ͳ͍ͨΊͷ
 ϊ΢ϋ΢ͷઆ໌͕ओʹͳ͍͖ͬͯ·͢ ͜͏ͨ͠ҙਤ͸ɺσόοά͸ඇޮ཰తͳ࡞ۀͰ͋Γɺ
 σόοάͷස౓ΛԼ͛Δ͜ͱ͕ͦ͜σόοάʹର͢Δ
 ༗ޮͳྟΈํͩͱ͍͏ࢲͷ৴೦͔Β͖͍ͯ·͢ ஫ҙॻ͖

Slide 12

Slide 12 text

ϊ΢ϋ΢ͷ঺հ ։ൃ଎౓Λ޲্ͤ͞Δ

Slide 13

Slide 13 text

--%#Λ࢖͍͜ͳ͢ Φεεϝ౓ʜ ϊ΢ϋ΢

Slide 14

Slide 14 text

σόοάͷ࣌ؒͰϦϏϧυʹ
 ͔͔͍ͬͯΔ࣌ؒ͸গͳ͘ͳ͍ ϦϏϧυΛආ͚ΒΕΕ͹
 σόοά࣌ؒΛ୹ॖͰ͖Δ

Slide 15

Slide 15 text

--%#ͱ͍͏σόοάπʔϧΛۦ࢖ͯ͠
 ࣍ͷͭͷํ๏ͰϦϏϧυΛආ͚ΒΕΔɿ ίʔϧελοΫΛḪΔ ϦϏϧυͳ͠Ͱ࠶࣮ߦ͢Δ ىಈͨ͠··ঢ়ଶΛมߋ͢Δ " # $

Slide 16

Slide 16 text

ϊ΢ϋ΢ʵ" ίʔϧελοΫΛḪΔ CSFBLQPJOUΛ࢖͏໨తͷͭ͸ɺ͋Δ࣌఺ͷ
 ม਺ͳͲΛ֬ೝ͢Δ͜ͱ Կ͔͓͔͚͠Ε͹ɺ΋͏গ͠աڈʹḪͬͯ
 ม਺Λ֬ೝ͢Δ͜ͱʹͳΔ ͜ΕΛCSFBLQPJOUͷషΓ௚͠ͱ
 ϦϏϧυͰ΍Δͱ͕͔͔࣌ؒΔ

Slide 17

Slide 17 text

ίʔϧελοΫʹ࢒͍ͬͯΔม਺ͳΒɺ
 ϦϏϧυ͠ͳ͍Ͱ΋֬ೝͰ͖Δ ࣮͸

Slide 18

Slide 18 text

ίʔϧελοΫͱ͸ʜʁ

Slide 19

Slide 19 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ᶃؔ਺Λ࣮ߦ ίʔϧελοΫ

Slide 20

Slide 20 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺ ؔ਺͕ݺͼग़͞ΕΔͱɺ
 ελοΫϑϨʔϜ͕࡞੒͞Εɺ
 ίʔϧελοΫʹੵ·ΕΔ

Slide 21

Slide 21 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ᶄ಺෦Ͱؔ਺Λ࣮ߦ ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺

Slide 22

Slide 22 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺ Ҿ਺ ϩʔΧϧม਺ CBS"SH CBS7BS CBSؔ਺ ݺͼग़͞Εͨؔ਺ͷதͰ
 ͞Βʹผͷؔ਺͕ݺ͹Εͯ΋
 ίʔϧελοΫʹੵ·ΕΔ

Slide 23

Slide 23 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ᶅ͞Βʹ಺෦Ͱؔ਺Λ࣮ߦ ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺ Ҿ਺ ϩʔΧϧม਺ CBS"SH CBS7BS CBSؔ਺

Slide 24

Slide 24 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺ Ҿ਺ ϩʔΧϧม਺ CBS"SH CBS7BS CBSؔ਺ Ҿ਺ ϩʔΧϧม਺ CB["SH CB[7BS CB[ؔ਺ ίʔϧελοΫʹੵ·ΕΔ

Slide 25

Slide 25 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ᶆϒϨʔΫϙΠϯτͰࢭΊΔ ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺ Ҿ਺ ϩʔΧϧม਺ CBS"SH CBS7BS CBSؔ਺ Ҿ਺ ϩʔΧϧม਺ CB["SH CB[7BS CB[ؔ਺

Slide 26

Slide 26 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺ Ҿ਺ ϩʔΧϧม਺ CBS"SH CBS7BS CBSؔ਺ Ҿ਺ ϩʔΧϧม਺ CB["SH CB[7BS CB[ؔ਺ ࢭ·ͬͨ࣌ʹݟ͍͑ͯΔ΋ͷ

Slide 27

Slide 27 text

func foo(_ fooArg: Int) { let fooVar = fooArg + 5 bar(fooVar) } func bar(_ barArg: Int) { let barVar = barArg * 7 baz(barVar) } func baz(_ bazArg: Int) { let bazVar = "\(bazArg)" print(bazVar) } ίʔϧελοΫ Ҿ਺ ϩʔΧϧม਺ GPP"SH GPP7BS GPPؔ਺ Ҿ਺ ϩʔΧϧม਺ CBS"SH CBS7BS CBSؔ਺ Ҿ਺ ϩʔΧϧม਺ CB["SH CB[7BS CB[ؔ਺ ࣮͸શ෦--%#͔ΒݟΒΕΔ

Slide 28

Slide 28 text

9DPEF "QQ$PEF ίʔϧελοΫͷḪΓํ ͕͜͜ίʔϧελοΫ

Slide 29

Slide 29 text

9DPEF "QQ$PEF ݟ͍ͨελοΫϑϨʔϜΛબ΂Δ ίʔϧελοΫͷḪΓํ

Slide 30

Slide 30 text

9DPEF "QQ$PEF ͦͷ࣌఺ͷม਺΍Ҿ਺ΛݟΒΕΔ ίʔϧελοΫͷḪΓํ

Slide 31

Slide 31 text

ϊ΢ϋ΢ʵ# ϦϏϧυͳ͠Ͱ࠶࣮ߦ͢Δ ίʔϧελοΫΛḪΔํ๏Ͱ͸ɺ͢Ͱʹ
 ࣮ߦ͕ऴΘͬͯ͠·ͬͨؔ਺ͷม਺ΛݟΒΕͳ͍ ͦͷ৔߹͸࠶࣮ߦ͠ͳ͚Ε͹ͳΒͳ͍͕ɺίʔυʹ
 มߋΛՃ͍͑ͯͳ͚Ε͹ϦϏϧυ͠ͳ͍Ͱ
 ࠶࣮ߦͨ͠΄͏͕࣌ؒΛઅ໿Ͱ͖Δ

Slide 32

Slide 32 text

9DPEF ϦϏϧυͳ͠ͷ࠶࣮ߦͷ΍Γํ "QQ$PEF ᶃϏϧυઃఆฤू ᶄ࠶࣮ߦ͍ͨ͠
 ઃఆΛίϐʔ ᶅ#VJMEΛ࡟আ ᶆ࡞੒ͨ͠ઃఆΛ࣮ߦ ΞϓϦΛ࠶ىಈͯ͠
 "UUBDIUP1SPDFTTͰ΋
 ࣅͨΑ͏ͳ͜ͱΛͰ͖·͢ ผͷํ๏

Slide 33

Slide 33 text

ϊ΢ϋ΢ʵ$ ىಈͨ͠··ঢ়ଶΛมߋ͢Δ ม਺ͷ಺༰Λॻ͖׵͑Δ͚ͩͳΒɺ
 ϦϏϧυͳ͠Ͱ΋Մೳ ίʔυม਺ͷ಺༰ΛҰ࣌తʹॻ͖׵͑ͯ
 ಈ࡞Λ͔֬Ί͍ͨ৔߹ʹศར σβΠφʔͱͷ࣮ػ֬ೝͳͲͰ
 Α͘ॏๅͨ͠ςΫχοΫ

Slide 34

Slide 34 text

มߋΛ࢝ΊΔͨΊͷҰ࣌ఀࢭͷ΍Γํ 9DPEF "QQ$PEF

Slide 35

Slide 35 text

--%#ͷೖྗΠϯλʔϑΣʔεΛ֬ೝ 9DPEF "QQ$PEF --%#ͷίϚϯυϥΠϯΠϯλʔϑΣʔε͕ىಈ͢Δ

Slide 36

Slide 36 text

(lldb) help Debugger commands: apropos -- List debugger commands related to a breakpoint -- Commands for operating on breakpoint shorthand.) ... IFMQΛ࣮ߦ͢Δͱɺ࣮ߦͰ͖Δૢ࡞ͷҰཡ͕දࣔ͞ΕΔ

Slide 37

Slide 37 text

(lldb) help po
 Evaluate an expression on the current
 thread. Displays any returned value
 with formatting controlled by the type's
 author. Expects 'raw' input (see 'help
 raw-input'.) ࠓճ͸--%#ܦ༝ͰίʔυΛ࣮ߦ͢ΔQPΛ࢖͏ ҙ༁: ݱࡏͷεϨουͰίʔυΛධՁ͠ɺ݁Ռͷ
 ஋ΛਓؒʹಡΈ΍͍͢ܗͰදࣔ͠·͢ɻ

Slide 38

Slide 38 text

(lldb) po print("Hello, World") error: use of undeclared identifier 'print' QPίϚϯυͰ)FMMP 8PSMEΛදࣔͯ͠ΈΑ͏ "QQ$PEFͷਓ͸͜ͷΤϥʔ͕ग़ͳ͍͔΋

Slide 39

Slide 39 text

ݱࡏͷελοΫϑϨʔϜΛ֬ೝ 9DPEF "QQ$PEF 4XJGUͷελοΫϑϨʔϜ΁Ҡಈ ࠷ॳ͔Β4XJGUͷελοΫϑϨʔϜΛ
 બ୒ͯ͘͠Ε͍ͯΔ͜ͱ͕ଟ͍

Slide 40

Slide 40 text

(lldb) po print("Hello, World") Hello, World ΋͏Ұ౓QPίϚϯυͰ)FMMP 8PSMEΛදࣔͯ͠ΈΑ͏ ͏·࣮͘ߦͰ͖ͨ

Slide 41

Slide 41 text

QPίϚϯυΛ࢖͏ͱɺىಈதͷΞϓϦͷ
 ద౰ͳ6*7JFXͷঢ়ଶΛม͑ΒΕΔ ͜ͷදࣔจࣈྻΛม͑ͯΈΑ͏

Slide 42

Slide 42 text

(lldb) po UIApplication.shared.keyWindow!
 .value(forKey: "recursiveDescription")! (layer) ·ͣɺදࣔ͞Ε͍ͯΔ6*7JFXͷҰཡΛදࣔ

Slide 43

Slide 43 text

(lldb) po UIApplication.shared.keyWindow!
 .value(forKey: "recursiveDescription")! (layer) දࣔ͞Ε͍ͯΔΫϥεͷܕ΍ϝϞϦΞυϨεΛೖखͰ͖Δ

Slide 44

Slide 44 text

(lldb) po let $label = unsafeBitCast(0x7fbee0610fe0, to: UILabel.self) ܕͱϝϞϦΞυϨε͕Θ͔ΔͱɺunsafeBitCastͰ
 ΠϯελϯεΛऔಘͰ͖Δ

Slide 45

Slide 45 text

(lldb) po let $label = unsafeBitCast(0x7fbee0610fe0, to: UILabel.self) ม਺΍ؔ਺ͳͲͷએݴΛ͢Δ৔߹͸ɺ໊લΛ͔Β࢝Ίͳ͍ͱແࢹ͞ΕΔͷͰ஫ҙ

Slide 46

Slide 46 text

(lldb) po $label

Slide 47

Slide 47 text

(lldb) po $label.text = "Hello, World!" $label ͷςΩετΛॻ͖׵͑ͯΈΑ͏

Slide 48

Slide 48 text

ΞϓϦͷ࣮ߦΛ࠶։͢Δ΍Γํ 9DPEF "QQ$PEF

Slide 49

Slide 49 text

UILabelͷද͕ࣔมΘͬͨʂ

Slide 50

Slide 50 text

5*14 ελοΫϑϨʔϜΛม͑ΔҎ֎ͷํ๏ ઌ΄Ͳ͸ελοΫϑϨʔϜΛ4XJGUͷ΋ͷʹ
 ߹Θͤͳ͍ͱΤϥʔʹͳ͍ͬͯͨ ࣮͸ɺԼͷΑ͏ʹ࣮ߦ͢ΔͱɺελοΫϑϨʔϜΛ
 ม͑ͳͯ͘΋Τϥʔ͸ൃੜ͠ͳ͍ ҙຯ͸help expr Ͱௐ΂ͯΈΑ͏ (lldb) expr -l swift -o -- print("Hello, World") ൃ ද Ͱ ͸ ׂ Ѫ

Slide 51

Slide 51 text

ݟͨ໨ͷมߋΛ΋ͬͱ؆୯ʹ 3FWFBMͱ͍͏ΞϓϦʢ༗ྉʣ͕ͱͯ΋ศར
 'SFF5SJBM͕͋ΔͷͰɺࢼͯ͠ΈΔͱ͍͍͔΋ʁ ྫ͑͹6*-BCFMͷ
 ςΩετΛม͑ΒΕΔ ಛʹ"VUP-BZPVUͷ
 σόοάʹॏๅ͢Δ https://revealapp.com 5*14 ൃ ද Ͱ ͸ ׂ Ѫ

Slide 52

Slide 52 text

ϊ΢ϋ΢ͷ·ͱΊ σόοΨΛ࢖͏ͱͭͷํ๏Ͱ
 ϦϏϧυΛආ͚ΒΕΔɿ ίʔϧελοΫΛḪΔ ϦϏϧυͳ͠Ͱ࠶࣮ߦ͢Δ ىಈͨ͠··ঢ়ଶΛมߋ͢Δ " # $

Slide 53

Slide 53 text

σόοάͷλΠϛϯάΛ
 มߋ௚ޙʹ͢Δ ϊ΢ϋ΢ Φεεϝ౓ʜ

Slide 54

Slide 54 text

ݪҼͷજΉൣғΛߜΓࠐΉͷ΋
 σόοά࣌୹ͷ༗ޮͳςΫχοΫ

Slide 55

Slide 55 text

GVODDMBTTTUSVDUFOVNͱ͍ͬͨ
 খ͞ͳ୯Ґͷ࣮૷௚ޙʹσόοάΛ
 ͢Ε͹ɺݪҼ͸௚લͷൣғʹߜΒΕΔ ۩ମతʹ͸

Slide 56

Slide 56 text

ॏཁͳͷ͸ɺมߋͱ֬ೝͷαΠΫϧΛ
 ͳΔ΂͘୹ִ͍ؒͰճͤΔΑ͏ʹอͭ͜ͱ ίʔυͷ
 มߋ ಈ࡞֬ೝ

Slide 57

Slide 57 text

struct Example { static func intToString(_ i: Int?) -> String { let x: Int! = i return "\(x)" } } ྫ͑͹ɺ੔਺Λਐ਺දهͷจࣈྻ΁
 ม׵͢ΔίʔυΛ࣮૷ͨ͠ͱ͢Δ ྫ͑͹ɺΛҾ਺ʹ͢Ε͹ɺਐ਺
 จࣈྻͰ͋Δ͕ฦ͖ͬͯͯ΄͍͠

Slide 58

Slide 58 text

ผͷίʔυͰ࢖͏લʹ--%#Ͱಈ࡞Λ֬ೝ͠Α͏ ʢ--%#͸ΞϓϦͷҰ࣌ఀࢭͰىಈͰ͖Δʣ (lldb) po Example.intToString(42)

Slide 59

Slide 59 text

(lldb) po Example.intToString(42) "Optional(42)"

Slide 60

Slide 60 text

struct Example { static func intToString(_ i: Int?) -> String { let x: Int! = i return "\(x)" } } όάΛݟ͚ͭͨΒ௚લͷ࣮૷Օॴʹ໭Ζ͏

Slide 61

Slide 61 text

struct Example { static func intToString(_ i: Int?) -> String { let x: Int = i! return "\(x)" } } Int!ΛจࣈྻԽ͢Δͱ"Optional(...)"ʹ
 ͳͬͯ͠·͏ͷͰɺIntʹͳΔΑ͏मਖ਼͢Δ

Slide 62

Slide 62 text

struct Example { static func intToString(_ i: Int?) -> String { let x: Int! = i return "\(x)" } } ࣮૷௚ޙʹσόοάͨ͠ͷͰɺ
 ݪҼՕॴ͕͙ۙ͘͢ʹݟ͔ͭͬͨ

Slide 63

Slide 63 text

मਖ਼ͨ͠Βɺ·͙ͨ͢ʹಈ࡞֬ೝ͠Α͏ (lldb) po Example.intToString(42) "42" ࠓ౓͸େৎ෉ͦ͏ͩ

Slide 64

Slide 64 text

5*14 --%#ͰCSFBLQPJOUΛޮ͔ͤΔํ๏ --%#ͷpo΍exprʹΑΔ࣮ߦͰCSFBLQPJOU͕
 ޮ͔ͳͯ͘ࠔΔ͜ͱ͕͋Δ ͦ͜Ͱɺexprͷ-iΦϓγϣϯΛfalseʹ͢Δͱɺ
 --%#͔Βͷ࣮ߦͰ΋CSFBLQPJOU͕ޮ͘Α͏ʹͳΔ (lldb) expr -l swift -o -i false -- Example.intToString(42) ൃ ද Ͱ ͸ ׂ Ѫ

Slide 65

Slide 65 text

ϊ΢ϋ΢ͷ·ͱΊ ͳΔ΂͘୹͘ૉૣ͘ճ͢ ίʔυͷ
 มߋ ಈ࡞֬ೝ

Slide 66

Slide 66 text

ෆ҆ۦಈͰηϧϑνΣοΫ͢Δ ϊ΢ϋ΢ Φεεϝ౓ʜ

Slide 67

Slide 67 text

Α͋͘Δ։ൃ଎౓௿ԼͷݪҼ͸ख໭Γ ࣗ෼ͷಈ࡞֬ೝ͕ෆ׬શͩͬͨΓɺ
 ࢥ͍΋͔ͭͳ͍όά͕͋ͬͨΓ͢Δͱ
 σόοά·Ͱख໭Γͯ͠͠·͏

Slide 68

Slide 68 text

͕࣌ؒܦͭ΄ͲݪҼ͕Θ͔Βͳ͘ͳΔ ༨ܭͳίϛϡχέʔγϣϯ͕૿͑Δ కΊ੾Γ௒աͷ࠷ޙͷҰԡ͠͸͍͍ͩͨख໭Γ ख໭ΓʹΑͬͯੜ͡Δ໰୊

Slide 69

Slide 69 text

͕࣌ؒܦͭ΄ͲݪҼ͕Θ͔Βͳ͘ͳΔ ͜ΕมͳͷͰݟͯ΋Β͑·͢ʁ ઌि࣮૷ͨ͠΍͚ͭͩͲ
 ͲΜͳײ͡ʹ͚ͨͬ͠ʜʁ ಈ࡞֬ೝ୲౰ ࣮૷ऀ

Slide 70

Slide 70 text

༨ܭͳίϛϡχέʔγϣϯ͕૿͑Δ ͜Εόάͬͯ·ͤΜ͔ʁ खॱΛڭ͑ͯ΋Β͑·͔͢ʁ ͑ʔͱɺ"Λ#͔ͯ͠Βʜ ಈ࡞֬ೝ୲౰ ࣮૷ऀ

Slide 71

Slide 71 text

కΊ੾Γ௒աͷ࠷ޙͷҰԡ͠͸͍͍ͩͨख໭Γ ࣮૷ ࣮૷ ࣮૷ ϨϏϡʔ ϨϏϡʔ ϨϏϡʔ ಈ࡞֬ೝ ख໭ΓରԠ ಈ࡞֬ೝ ਓ਺Ͱεέʔϧ͠ͳ͍ $͞Μ ,VOJXBL "͞Μ #͞Μ

Slide 72

Slide 72 text

ͳΔ΂ࣗ͘෼ͰόάΛݟ͚ͭͯɺ
 ख໭ΓΛݮΒ͍ͯ͘͜͠ͱ͕ॏཁ ଟগ͕͔͔࣌ؒͬͨͱͯ͠΋ɺ
 ͋ͱͰݟ͔ͭΔΑ͏ͳόάͰ
 ख໭Γ͠ͳ͚Ε͹શମతͳ
 ࣌ؒ͸Ή͠ΖݮΔ ͭ·Γ

Slide 73

Slide 73 text

Ͳ͜·ͰΛηϧϑνΣοΫ͢Δ͔ ͱ͸͍͑

Slide 74

Slide 74 text

͜ͷ··ಥ͖ਐΉͱɺ͢΂ͯͷόάΛ
 શ෦ࣗ෼Ͱݟ͚ͭΔ͜ͱʹͳͬͯ
 ͠·Θͳ͍ͩΖ͏͔ʁ ͦΕ͸ਖ਼͍͠ํ਑ͳͷͩΖ͏͔ʁ

Slide 75

Slide 75 text

ࣗ෼ͰશͯΛݟ͚ͭΔ ख໭Γ࠷খ

Slide 76

Slide 76 text

ಈ࡞֬ೝ୲౰ͷਓͷ࣌ؒΛ
 ༗ޮ׆༻Ͱ͖ͳ͍ ख໭Γ࠷খ ෼ۀ࠷খ

Slide 77

Slide 77 text

࣮૷͚ͩʹઐ೦͢Δ ख໭Γ࠷খ ෼ۀ࠷খ ෼ۀ࠷େ

Slide 78

Slide 78 text

։ൃ͕࣌ؒ৳ͼΔ ख໭Γ࠷খ ෼ۀ࠷খ ෼ۀ࠷େ ख໭Γ࠷େ

Slide 79

Slide 79 text

ख໭Γ࠷খ ෼ۀ࠷খ ෼ۀ࠷େ ख໭Γ࠷େ ͲͪΒ΋ۃ୺ʹ͢Ε͹͕࣌ؒ૿͑ͯ͠·͏

Slide 80

Slide 80 text

Ͳ͔͜ͷଥڠ఺Λ
 બ͹ͳ͍ͱ͍͚ͳ͍ ͱ͍͏͜ͱ͸

Slide 81

Slide 81 text

ීวతʹ࠷దͳ
 ଥڠ఺͸ଘࡏ͠ͳ͍ ͔͠͠

Slide 82

Slide 82 text

͢΂ͯͷෆ҆ͳߦΛҰ౓͸
 ௨ա͢Δఔ౓Λ໨҆ʹͨ͠ ͦ͜ͰɺࢲͷࣄྫͰ͸

Slide 83

Slide 83 text

ෆ҆ͳίʔυͷྫ struct Example { static func intToString(_ i: Int?) -> String { let x: Int! = i return "\(x)" } } ͨͱ͑͹ɺઌ΄Ͳͷ୹͍ίʔυͷதʹ΋
 ෆ҆ͳ৔ॴ͕͋ͬͨ ࢲͷෆ҆ϙΠϯτ

Slide 84

Slide 84 text

"\(x)"͸ͱ͖Ͳ͖৴༻ͷͳΒͳ͍ڍಈΛ͢Δ Int?ͩͱμϝʹͳΔͷ͸༗໊ͳͷͰ
 ஌͍͕ͬͯͨɺInt!Ͱ΋ಉ͡Α͏ʹ
 μϝͳͷ͔Ͳ͏͔֬৴Λ΋ͯͳ͔ͬͨ ͦ͏͍͏࣌͸ɺ--%#ͳͲͰ
 ࣮ࡍʹಈ͔͔ͯ֬͠ΊΑ͏ --%#Ҏ֎ͷํ๏͸ϊ΢ϋ΢Ͱ΋঺հ

Slide 85

Slide 85 text

w සൟʹ௨ա͢Δ෼ذʢ͜͜ʹόά͕͋Δͱਃ͠༁ͳ͍ʣ if (x < 0)ͷ෼ذͰxʹͲΜͳ΋ͷ͕དྷΔ͔
 Θ͔Βͳ͍ͳΒɺগͳ͘ͱ΋ਖ਼ͱෛͷ྆ํΛࢼ͢ w ෼ذ৚݅ͷڥ໨ x < 0ͳΒڥ໨͸ɺ഑ྻ͸ۭͷͱ͖ʹڥ໨ʹͳΓ΍͍͢
 DoubleͳΒ+0 -0 +infinity -infinity nanͳͲ w ཧղͰ͖͍ͯͳ͍ίϯϙʔωϯτͷར༻ ྫ͑͹ɺඪ४ϥΠϒϥϦͷ6*5BCMF7JFX͸࢖͍ํ͕
 ͱͯ΋ෳࡶͳͷͰ͍ͭ΋ؒҧ͑ͯ͠·͏ ࢲͷ࠷ۙͷෆ҆ϙΠϯτ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 86

Slide 86 text

։ൃऀͷෆ҆͸ɺաڈʹࣗ਎͕౿Μͩ
 όάͷܦݧΛ൓ө͍ͯ͠Δ͔Β ͔͠͠ɺͳͥෆ҆ͱ͍͏ج४ͳͷ͔ʁ

Slide 87

Slide 87 text

ෆ҆ΛΞοϓσʔτ͠ଓ͚Δ͜ͱͰ
 ͦͷݱ৔ʹదͨ͠ଥڠ఺΁͍͍͚ۙͮͯΔ ෆ͕࣮҆ࡍͷόάͷ܏޲ʹ
 ݁ͼͭ͘Α͏ʹײ֮Λ
 ߋ৽͠ଓ͚Α͏

Slide 88

Slide 88 text

ϊ΢ϋ΢ͷ·ͱΊ ෆ͕҆ͳ͘ͳΔ·Ͱ
 ηϧϑνΣοΫ͠Α͏ ෆ҆ͷਫ਼౓Λ্͍͛ͯ͜͏

Slide 89

Slide 89 text

ಈ࡞֬ೝΛࣗಈԽ͢Δ ϊ΢ϋ΢ Φεεϝ౓ʜ

Slide 90

Slide 90 text

ϊ΢ϋ΢Λଥڠͤͣʹ
 ࣮ફ͢Δͷ͸͔ͳΓ೉͍͠ ͳͥͳΒɺෆ҆Λײ͡ΔՕॴ͸
 ࢥͬͨΑΓଟ͍͔Β ͢Δͱ్தͰଥڠ͕ͪ͠ʹͳΓɺ
 ख໭Γ͕ࢥͬͨΑΓ
 ݮΒͳ͘ͳΔ

Slide 91

Slide 91 text

Ͳ͜·Ͱ֬ೝ͢Ε͹҆৺Ͱ͖ΔͩΖ͏ʁ ཧ૝తͳൣғΛ૝૾ͯ͠ΈΑ͏

Slide 92

Slide 92 text

ࢲʹͱͬͯͷཧ૝తͳಈ࡞֬ೝ Өڹ͞ΕΔίϯϙʔωϯτ
 ͢΂ͯͬͯແཧͰ͸ʜʁ ͜Ε͸Ͱ͖ͦ͏ w ͦΕҎ֎ʹӨڹ͢Δίϯϙʔωϯτ΋
 ͢΂ͯ֬ೝ͠ͳ͍ͱຊདྷ͸·͍ͣ w ࣮૷मਖ਼ͨ͠ίϯϙʔωϯτΛ
 ֬৴Ͱ͖ΔϨϕϧ·Ͱ֬ೝ

Slide 93

Slide 93 text

w ͕͔͔࣌ؒΓ͗͢Δ w Өڹ͢Δίϯϙʔωϯτͷಈ࡞֬ೝͷ
 ࢓ํΛ͍֮͑ͯΔ͸͕ͣͳ͍ Өڹ͢ΔίϯϙʔωϯτΛ͢΂ͯ֬ೝ͢Δ
 ͱ͖ͷΑ͋͘Δ໰୊఺ɿ ͋Εʁ͜ͷڍಈͰ͋ͬͯΔΜ͚ͩͬʜʁ ਖ਼͍͠Ҿ਺ͬͯͲ͏΍ͬͯ࡞ΔΜ͚ͩͬʁ

Slide 94

Slide 94 text

ಈ࡞֬ೝΛࣗಈԽ͠Α͏ ͦ͏͍͏ͱ͖͸

Slide 95

Slide 95 text

ίʔυͷಈ࡞֬ೝΛࣗಈԽ͢Δར఺ɿ w ܁Γฦ࣮͠ߦ͢Δίετ͕௿͍ͷͰ
 ࣌ؒ͸ͦ͜·Ͱ͔͔Βͳ͘ͳΔ w ૢ࡞֬ೝͷखॱ͕ίʔυͱͯ͠
 ࢒͞ΕΔͷͰ΍ΓํΛ๨Εͳ͍

Slide 96

Slide 96 text

ಈ࡞֬ೝΛࣗಈԽ͢Δͭͷํ๏ɿ ಈ࡞֬ೝͷͨΊͷඪ४ϥΠϒϥϦΛ
 ࢖ͬͯಈ࡞֬ೝ "QQ%FMFHBUFܦ༝Ͱಈ࡞֬ೝ " #

Slide 97

Slide 97 text

ϊ΢ϋ΢ʵ" "QQ%FMFHBUFͰಈ࡞֬ೝ ಈ࡞֬ೝͷίʔυΛॻ͘ ৽͍͠4DIFNFΛ࡞੒͢Δ "QQ%FMFHBUFͰͷ
 4DIFNFͷͱ͖͚ͩΛ
 ࣮ߦ͢ΔΑ͏ʹ͢Δ ͨͩܽ͠఺͕ଟ͍ͷͰɺൃදͰ͸ׂѪ͠·͢

Slide 98

Slide 98 text

#if DEBUG import Foundation let debugTargets: [String: () -> Void] = [ "intToString": { let string = Example.intToString(42) guard string == "48" else { fatalError("intToString(42) ͕ \"42\" Λฦ͞ͳ͔ͬͨ") } }, ] func debugAll() { let targets = Array(debugTargets.values) DispatchQueue.concurrentPerform(iterations: targets.count) { index in targets[index]() } } #endif ಈ࡞֬ೝͷίʔυΛ·ͱΊΔ%JDUJPOBSZΛ࡞੒͢Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 99

Slide 99 text

#if DEBUG import Foundation let debugTargets: [String: () -> Void] = [ "intToString": { let string = Example.intToString(42) guard string == "42" else { fatalError("intToString(42) ͕ \"42\" Λฦ͞ͳ͔ͬͨ") } }, ] func debugAll() { let targets = Array(debugTargets.values) DispatchQueue.concurrentPerform(iterations: targets.count) { index in targets[index]() } } #endif ಈ࡞֬ೝͷίʔυΛॻ͘ ͜ͷίʔυ͸ɺintToString(42)ͷ
 ݁Ռ͕"42"ʹͳΔ͜ͱΛ֬ೝ͍ͯ͠Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 100

Slide 100 text

#if DEBUG import Foundation let debugTargets: [String: () -> Void] = [ "intToString": { let string = Example.intToString(42) guard string == "48" else { fatalError("intToString(42) ͕ \"42\" Λฦ͞ͳ͔ͬͨ") } }, ] func debugAll() { let targets = Array(debugTargets.values) DispatchQueue.concurrentPerform(iterations: targets.count) { index in targets[index]() } } #endif ͢΂ͯͷಈ࡞֬ೝίʔυΛ࣮ߦ͢Δ
 EFCVH"MMؔ਺Λ࣮૷͢Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 101

Slide 101 text

৽͍͠4DIFNFΛ࡞੒͢Δ΍Γํ 9DPEF ᶃ4DIFNFΛ࡞੒ ᶄద౰ͳ໊લΛ͚ͭΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 102

Slide 102 text

৽͍͠4DIFNFΛ࡞੒͢Δ΍Γํ ᶃϏϧυઃఆΛ։͘ ᶆద౰ͳ໊લΛ͚ͭΔ "QQ$PEF ᶅ"QQMJDBUJPOΛࢦఆ ᶄ4DIFNFΛ࡞੒ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 103

Slide 103 text

؀ڥม਺Λ௥Ճ͢Δ΍Γํ 9DPEF ᶃ4DIFNFΛฤू ᶄ؀ڥม਺Λ௥Ճ "QQ$PEF ᶃ؀ڥม਺Λฤू ᶄ؀ڥม਺Λ௥Ճ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 104

Slide 104 text

؀ڥઃఆͷ஋Λઃఆ͢Δ΍Γํ 9DPEF ᶃAUTO_DEBUG=1Λઃఆ "QQ$PEF ᶃAUTO_DEBUG=1Λઃఆ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 105

Slide 105 text

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: #if DEBUG if ProcessInfo.processInfo.environment["AUTO_DEBUG"] == "1" { debugAll() return true } #endif // ... return true } } "QQ%FMFHBUFʹ؀ڥม਺ͷ෼ذΛ௥Ճ AUTO_DEBUG=1ͷͱ͖ͷΈɺ
 ઌ΄ͲͷdebugAllΛ࣮ߦ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 106

Slide 106 text

ΞϓϦΛ࣮ߦͯ͠ΈΑ͏ ͦΕͰ͸ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 107

Slide 107 text

ΞϓϦΛ࣮ߦ͢Δͱಈ࡞֬ೝͰ͖Δ 9DPEF Ͳ͜Ͱࣦഊ͔ͨ͠Θ͔Δ ࣦഊͨ͠ཧ༝͕Θ͔Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 108

Slide 108 text

ΞϓϦΛ࣮ߦ͢Δͱಈ࡞֬ೝͰ͖Δ "QQ$PEF Ͳ͜Ͱࣦഊ͔ͨ͠Θ͔Δ ࣦഊͨ͠ཧ༝͕Θ͔Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 109

Slide 109 text

5*14 ࢦఆͨ͠ίʔυ͚ͩಈ࡞֬ೝ ݸผͷಈ࡞֬ೝ͚ͩΛ࣮ߦ͍ͨ͜͠ͱ͸Α͋͘Δ ͦ͏͍͏৔߹͸ɺ--%#͔Β໊લΛࢦఆͯ͠ݸผʹ
 ಈ࡞֬ೝΛ࣮ߦͰ͖Δ ಈ࡞֬ೝͷίʔυΛ഑ྻͰ͸ͳ͘%JDUJPOBSZʹ
 ֨ೲͨ͠ͷ͸͜Ε͕໨త (lldb) po debugTargets["intToString"]!() Fatal error: intToString(42) ͕ "42" Λฦ͞ͳ͔ͬͨ: ൃ ද Ͱ ͸ ׂ Ѫ

Slide 110

Slide 110 text

"QQ%FMFHBUFͷํ๏ͷ໰୊఺ɿ w ෳ਺ͷಈ࡞֬ೝ͕ࣦഊ͢Δͱɺઌʹ
 ࣮ߦ͞Εͨํ͔͠೺ѲͰ͖ͳ͍ w fatalErrorΛprint΁ม͑Ε͹
 ෳ਺ͷࣦഊΛ೺ѲͰ͖ΔΑ͏ʹ
 ͳΔ͕ɺࠓ౓͸ࣦഊͨ͠ࡍʹ*%&͕
 δϟϯϓͯ͘͠Εͳ͍ͷͰෆศ ͜ΕΒͷ໰୊͸ඪ४ϥΠϒϥϦͰղܾͰ͖·͢

Slide 111

Slide 111 text

ϊ΢ϋ΢ʵ# ඪ४ϥΠϒϥϦͰಈ࡞֬ೝ ৽͍͠5BSHFUΛ࡞੒͢Δ ಈ࡞֬ೝͷίʔυΛॻ͘ ಈ࡞֬ೝͷίʔυͷ5BSHFUΛ
 ઌ΄Ͳ࡞੒ͨ͠΋ͷʹ͢Δ J04ʹ͸ಈ࡞֬ೝ༻ͷඪ४ϥΠϒϥϦʮ9$5FTUʯ͕
 ༻ҙ͞Ε͍ͯΔ ͜ΕͰ"QQ%FMFHBUFʹ͋ͬͨෳ਺ࣦഊͨ͠ͱ͖ͷ
 ໰୊ΛղܾͰ͖Δ͕ɺ࣍ͷΑ͏ͳϏϧυઃఆ͕ඞཁɿ

Slide 112

Slide 112 text

Ϗϧυઃఆͷ΍Γํ 9DPEF ᶃ5BSHFUΛ৽ن࡞੒ ᶅඞཁ߲໨Λهೖ ᶄJ046OJU5FTUJOH#VOEMFΛબ୒ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 113

Slide 113 text

ᶃ1SPKFDU4FUUJOHTΛ։͘ ᶄ5BSHFUΛ௥Ճ ᶅJ046OJU5FTUJOH#VOEMFΛબ୒ Ϗϧυઃఆͷ΍Γํ "QQ$PEF ൃ ද Ͱ ͸ ׂ Ѫ

Slide 114

Slide 114 text

Ϗϧυઃఆͷ΍Γํ 9DPEF ᶆ5FTUJOHΛ࣮ߦ ᶇ5FTU4VDDFFEFE͕දࣔ͞ΕΕ͹0, ൃ ද Ͱ ͸ ׂ Ѫ

Slide 115

Slide 115 text

ᶇϏϧυઃఆΛฤू ᶈ4DIFNFΛ௥Ճ ᶆඞཁ߲໨Λهೖ Ϗϧυઃఆͷ΍Γํ "QQ$PEF ൃ ද Ͱ ͸ ׂ Ѫ

Slide 116

Slide 116 text

ᶌ"MM5FTUT1BTTFEͱදࣔ͞ΕΕ͹0, ᶉ9$5FTUΛબ୒ ᶊద౰ͳ໊લΛ͚ͭΔ ᶋ࡞੒ͨ͠4DIFNFΛ࣮ߦ Ϗϧυઃఆͷ΍Γํ "QQ$PEF ൃ ද Ͱ ͸ ׂ Ѫ

Slide 117

Slide 117 text

͜ΕͰಈ࡞֬ೝ༻ͷ5BSHFUΛ࡞੒Ͱ͖ͨ

Slide 118

Slide 118 text

import XCTest @testable import IOSDC2018Debugging class ExampleTest: XCTestCase { func testIntToString() { let str = Example.intToString(42) XCTAssertEqual(str, "42") } } ඪ४ϥΠϒϥϦΛ࢖͏৔߹ͷ
 ಈ࡞֬ೝͷίʔυ͸͜͏ͳΔ

Slide 119

Slide 119 text

import XCTest @testable import IOSDC2018Debugging class ExampleTest: XCTestCase { func testIntToString() { let str = Example.intToString(42) XCTAssertEqual(str, "42") } } ಈ࡞֬ೝͷίʔυͷUBSHFU͸
 ઌ΄Ͳ࡞੒ͨ͠UBSHFUʹ͢Δ

Slide 120

Slide 120 text

9DPEF ᶃ࡞੒ͨ͠5BSHFUΛબ୒ "QQ$PEF ൃ ද Ͱ ͸ ׂ Ѫ ᶃ.BOBHF5BSHFUTΛબ୒ ᶄ࡞੒ͨ͠5BSHFUΛબ୒ 5BSHFUͷࢦఆͷ΍Γํ

Slide 121

Slide 121 text

import XCTest @testable import IOSDC2018Debugging class ExampleTest: XCTestCase { func testIntToString() { let str = Example.intToString(42) XCTAssertEqual(str, "42") } } ඪ४ϥΠϒϥϦ9$5FTUΛಡΈࠐΉ ΞϓϦͷίʔυ͸ผͷ5BSHFUͳͷͰ
 ࢖͏ࡍʹ͸import͕ඞཁ ී௨ʹimport͢Δͱpublicͷ΋ͷ͔͠
 ݟ͑ͳ͘ͳͬͯ͠·͏͕ɺ@testableΛͭ ͚Δͱinternal·Ͱݟ͑ΔΑ͏ʹͳΔ

Slide 122

Slide 122 text

import XCTest @testable import IOSDC2018Debugging class ExampleTest: XCTestCase { func testIntToString() { let str = Example.intToString(42) XCTAssertEqual(str, "42") } } ಈ࡞֬ೝͷίʔυ͸XCTestCaseͱ͍͏
 ΫϥεͰάϧʔϐϯάͰ͖ΔΑ͏ʹͳ͍ͬͯΔ ಈ࡞֬ೝͷίʔυΛॻ͘৔߹ʹ͸ɺ֬ೝର৅ͷ
 Ϋϥε΍ؔ਺୯ҐͰXCTestCaseΛ෼͚Δͱ
 ಈ࡞֬ೝͷ݁Ռ͕Θ͔Γ΍͘͢ͳΔ

Slide 123

Slide 123 text

import XCTest @testable import IOSDC2018Debugging class ExampleTest: XCTestCase { func testIntToString() { let str = Example.intToString(42) XCTAssertEqual(str, "42") } } ࣮ࡍͷಈ࡞֬ೝͷίʔυ͸ɺΠϯελϯεϝιουͱ࣮ͯ͠૷͢Δ ͜ͷϝιουͷ໊લ͸ઌ಄ʹtestͱ͚ͭͳ͍ͱ࣮ߦ͞Εͳ͍ͷͰ஫ҙ

Slide 124

Slide 124 text

import XCTest @testable import IOSDC2018Debugging class ExampleTest: XCTestCase { func testIntToString() { let str = Example.intToString(42) XCTAssertEqual(str, "42") } } ಈ࡞֬ೝͷର৅Λ࣮ࡍʹ࣮ߦ͢Δ

Slide 125

Slide 125 text

import XCTest @testable import IOSDC2018Debugging class ExampleTest: XCTestCase { func testIntToString() { let str = Example.intToString(42) XCTAssertEqual(str, "42") } } ਖ਼ޡ൑ఆ͸XCTAssertEqualͳͲͷؔ਺Λ࢖͏ ͜ͷؔ਺͸ɺͭͷҾ਺͕౳͘͠ͳ͍ͱɺ
 ಈ࡞֬ೝΛࣦഊͱΈͳ͢Α͏ʹͳ͍ͬͯΔ

Slide 126

Slide 126 text

ඪ४ϥΠϒϥϦΛ࢖ͬͨ݁Ռը໘ 9DPEF Ͳ͜Ͱࣦഊ͔ͨ͠Θ͔Δ ࣦഊͨ͠ཧ༝΋Θ͔Δ ෳ਺ͷࣦഊ͕
 ҰཡͰݟΒΕΔ

Slide 127

Slide 127 text

"QQ$PEF Ͳ͜Ͱࣦഊ͔ͨ͠Θ͔Δ ෳ਺ͷࣦഊ͕
 ҰཡͰݟΒΕΔ ࣦഊͨ͠ཧ༝΋Θ͔Δ ඪ४ϥΠϒϥϦΛ࢖ͬͨ݁Ռը໘ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 128

Slide 128 text

ඪ४ϥΠϒϥϦͷํ๏ͷ໰୊఺ɿ w Ϗϧυઃఆ͕յΕ͍ͯΔͱɺ௚͢·Ͱ
 ಈ࡞֬ೝͷίʔυΛ࣮ߦͰ͖ͳ͍ w ઃఆΛ͙͢ʹ͸௚ͤͳͦ͞͏ͳΒɺ
 "QQ%FMFHBUFͷํ๏ΛҰ࣌తʹ
 ࢖͏ͷ΋༗ޮͳखஈ ͋Γ͕ͪͳͷ͕
 Կ͔ͷϥΠϒϥϦͷ
 4FBSDI1BUITͷ
 ઃఆ΋Ε

Slide 129

Slide 129 text

ϊ΢ϋ΢ͷ·ͱΊ ಈ࡞֬ೝΛࣗಈԽ͢Δͭͷํ๏ɿ ಈ࡞֬ೝͷͨΊͷඪ४ϥΠϒϥϦΛ
 ࢖ͬͯಈ࡞֬ೝ "QQ%FMFHBUFܦ༝Ͱಈ࡞֬ೝ " # #ͷํ͕Φεεϝ͕ͩɺ͙͢ʹ͸೉ͦ͠͏ͳΒҰ࣌తʹ"Ͱ΋0,ʂ

Slide 130

Slide 130 text

ؒҧ͍ʹ͍͘ઃܭʹ͢Δ ϊ΢ϋ΢ ൃ ද Ͱ ͸ ׂ Ѫ Φεεϝ౓ʜ

Slide 131

Slide 131 text

σόοάΛͦ΋ͦ΋͍Βͳ͍Α͏ʹͰ͖ΔͳΒ
 ͦΕ͕Ұ൪࣌ؒΛ୹ॖͰ͖Δ ྫͱͯ࣍͠ͷΑ͏ͳ޻෉Λ঺հ͢Δɿ Կ͔ͷ*%Λ௚઀ͷ*OU΍4USJOHʹ͠ͳ͍ ίʔυΛࣗಈੜ੒͢Δ " # ൃ ද Ͱ ͸ ׂ Ѫ

Slide 132

Slide 132 text

ϊ΢ϋ΢ʵ" *%ΛݸผͷTUSVDUʹ͢Δ ΞϓϦΛ࡞੒͍ͯ͠Δͱෳ਺ͷछྨͷ*%Λ
 औΓѻ͏͜ͱ͕ଟ͍ʢ6TFS*%΍$PNNFOU*%ͳͲʣ ͜ͷ*%ΛऔΓҧ͑ͯॲཧͯ͠͠·ͬͨΓ͢Δͱɺ
 ݪҼಛఆ͕େมͳ໘౗ͳόάΛੜΈग़͠΍͍͢ ͜͏͍͏࣌͸ɺࢥ͍੾ͬͯݸผͷ
 TUSVDU΁෼͚ͯ͠·͓͏ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 133

Slide 133 text

*%ΛݸผͷTUSVDU΁෼͚ͨྫ // BAD: औΓҧ͑ͯ΋ؾ͖ͮͮΒ͍ let userID: Int = 1234 let productID: Int = 5678 // GOOD: औΓҧ͑ΔͱίϯύΠϧΤϥʔʹͳΔ let userID = UserID(number: 1234) let productID = ProductID(number: 5678) ൃ ද Ͱ ͸ ׂ Ѫ

Slide 134

Slide 134 text

ϊ΢ϋ΢ʵ# ίʔυΛࣗಈੜ੒͢Δ Α͋͘ΔόάͷݪҼʹ6*4UPSZCPBSE΍6*/JCͷ
 ໊લࢦఆͷϛε΍ϦωʔϜ๨Ε͕͋Δ ͜ΕΒͷίʔυΛࣗಈੜ੒ͯ͘͠ΕΔπʔϧ͕
 ͍͔ͭ͋͘ΔͷͰɺͲΕ͔Λ࢖͑͹͜ͷछͷόάΛ
 ࣄલʹ༧๷Ͱ͖Δɿ w HJUIVCDPNNBDDBJO3TXJGU w HJUIVCDPN4XJGU(FO4XJGU(FO ൃ ද Ͱ ͸ ׂ Ѫ

Slide 135

Slide 135 text

ϊ΢ϋ΢ͷ·ͱΊ ͜ͷछͷςΫχοΫ͸ແ਺ʹ͋ΔͨΊɺ
 ঺հͨ͠ͷ͸͘͝Ұ෦ Կ͔ͷ*%Λ௚઀ͷ*OU΍
 4USJOHʹ͠ͳ͍ ίʔυΛࣗಈੜ੒͢Δ " # ൃ ද Ͱ ͸ ׂ Ѫ

Slide 136

Slide 136 text

վળલͱͷൺֱ ײ͍ͯͩ͘͡͞

Slide 137

Slide 137 text

్த·Ͱ͏·͍͘͘ͷʹ
 కΊ੾Γʹؒʹ߹Θͳ͍

Slide 138

Slide 138 text

ෆ҆ۦಈνΣοΫͰख໭Γ͕
 গͳ͘ͳͬͨͷͰɺ༧ఆ௨Γʹ
 ਐΉΑ͏ʹͳͬͨʂ

Slide 139

Slide 139 text

కΊ੾Γ͕ഭͬͯ͘Δͱ
 ಈ࡞֬ೝΛ͖͠Εͳͯ͘
 େৎ෉ͩͱ৴͡Δ͔͠ͳ͍

Slide 140

Slide 140 text

ಈ࡞֬ೝͷࣗಈԽͰɺӨڹൣғͷ
 ಈ࡞֬ೝ·ͰͰ͖ΔΑ͏ʹͳͬͨʂ

Slide 141

Slide 141 text

4JNVMBUPSΆͪΆͪʹ
 ͕͔͔࣌ؒͬͯΠϥΠϥ͢Δ

Slide 142

Slide 142 text

ಈ࡞֬ೝͷࣗಈԽͰ
 ΆͪΆ͍ͪΒͳ͘ͳͬͨʂ

Slide 143

Slide 143 text

͜͏͍͏खॱ·Ͱ͍࣋ͬͯͬͨ݁Ռɺ
 ։ൃ଎౓͕ʹͳͬͯ·ͨ͠ څྉ্͕͕ͬͨ
 ,VOJXBL ࢲͷࣄྫͰ͸

Slide 144

Slide 144 text

࣮ࡍ͸͜Μͳʹ
 ͢ΜͳΓ͍͔ͳ͍ Τ ο ʂ ʁ

Slide 145

Slide 145 text

ࣗಈԽͷ୩໰୊ ཱͪ͸͔ͩΔ

Slide 146

Slide 146 text

ϊ΢ϋ΢dͷ࣮ફ͕ͱͯ΋೉͍͠ ͜ͷ͋ͱྫΛग़͕͢ɺࣗಈͰͷ
 ಈ࡞֬ೝ͸༧૝֎ʹͰ͖ͳ͍΋ͷ ࣮͸ʜ

Slide 147

Slide 147 text

import UIKit class ExampleViewController: UIViewController { @IBOutlet weak var label: UILabel! @IBAction func buttonTapped(_ sender: Any) { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { dump(error) let alertViewController = UIAlertController( title: "Τϥʔ͕ൃੜ͠·ͨ͠", message: nil, preferredStyle: .alert ) alertViewController.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } ಈ࡞֬ೝͷࣗಈԽ͕͔ͳΓ೉͍͠ྫ

Slide 148

Slide 148 text

͜Μͳ୯७ͳ7JFX$POUSPMMFSͰ΋ɺ ಈ࡞֬ೝΛࣗಈԽ͢ΔͨΊͷ஌͕ࣝ
 ͔ͳΓଟ͍ͱ͍͏͜ͱΛײ͡Ͱ͍ͩ͘͞

Slide 149

Slide 149 text

import UIKit class ExampleViewController: UIViewController { @IBOutlet weak var label: UILabel! @IBAction func buttonTapped(_ sender: Any) { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { dump(error) let alertViewController = UIAlertController( title: "Τϥʔ͕ൃੜ͠·ͨ͠", message: nil, preferredStyle: .alert ) alertViewController.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } Ϙλϯ͕λοϓ͞ΕͨΒ
 αʔόͱ௨৴Λ࢝ΊΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 150

Slide 150 text

import UIKit class ExampleViewController: UIViewController { @IBOutlet weak var label: UILabel! @IBAction func buttonTapped(_ sender: Any) { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { dump(error) let alertViewController = UIAlertController( title: "Τϥʔ͕ൃੜ͠·ͨ͠", message: nil, preferredStyle: .alert ) alertViewController.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } αʔόʔͱͷ௨৴͕
 Τϥʔʹͳͬͨ৔߹͸
 6*"MFSU$POUSPMMFSͰදࣔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 151

Slide 151 text

import UIKit class ExampleViewController: UIViewController { @IBOutlet weak var label: UILabel! @IBAction func buttonTapped(_ sender: Any) { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { dump(error) let alertViewController = UIAlertController( title: "Τϥʔ͕ൃੜ͠·ͨ͠", message: nil, preferredStyle: .alert ) alertViewController.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } αʔόʔ͔ΒϢʔβʔ໊͕
 ਖ਼ৗʹฦ͖ͬͯͨΒදࣔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 152

Slide 152 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let viewController = UIStoryboard( name: "ExampleViewController", bundle: Bundle(for: ExampleViewController.self) ).instantiateInitialViewController() as! ExampleViewController let dummySender = NSObject() viewController.buttonTapped(dummySender) XCTAssertTrue(viewController.label?.text?.contains("Kuniwak")) } } ͱΓ͋͑ͣಈ࡞֬ೝͷίʔυΛॻ͍ͯΈͨ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 153

Slide 153 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let viewController = UIStoryboard( name: "ExampleViewController", bundle: Bundle(for: ExampleViewController.self) ).instantiateInitialViewController() as! ExampleViewController let dummySender = NSObject() viewController.buttonTapped(dummySender) XCTAssertTrue(viewController.label!.text!.contains("Kuniwak")) } } 4UPSZCPBSE͔Β7JFX$POUSPMMFSΛॳظԽ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 154

Slide 154 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let viewController = UIStoryboard( name: "ExampleViewController", bundle: Bundle(for: ExampleViewController.self) ).instantiateInitialViewController() as! ExampleViewController let dummySender = NSObject() viewController.buttonTapped(dummySender) XCTAssertTrue(viewController.label!.text!.contains("Kuniwak")) } } @IBActionΛ࣮ߦͯ͠ϘλϯλοϓΛ࠶ݱ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 155

Slide 155 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let viewController = UIStoryboard( name: "ExampleViewController", bundle: Bundle(for: ExampleViewController.self) ).instantiateInitialViewController() as! ExampleViewController let dummySender = NSObject() viewController.buttonTapped(dummySender) XCTAssertTrue(viewController.label!.text!.contains("Kuniwak")) } } UILabel͕Ϣʔβʔ໊ʹมΘͬͨ͜ͱΛ֬ೝ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 156

Slide 156 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let viewController = UIStoryboard( name: "ExampleViewController", bundle: Bundle(for: ExampleViewController.self) ).instantiateInitialViewController() as! ExampleViewController let dummySender = NSObject() viewController.buttonTapped(dummySender) XCTAssertTrue(viewController.label!.text!.contains("Kuniwak")) } } viewController.label͕nil ൃ ද Ͱ ͸ ׂ Ѫ

Slide 157

Slide 157 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let viewController = UIStoryboard( name: "ExampleViewController", bundle: Bundle(for: ExampleViewController.self) ).instantiateInitialViewController() as! ExampleViewController let dummySender = NSObject() viewController.buttonTapped(dummySender) XCTAssertTrue(viewController.label!.text!.contains("Kuniwak")) } } viewDidLoadΛ଴ͬͯͳ͍ͷͰɺ
 ·ͩUILabel͕ଘࡏ͍ͯ͠ͳ͍ ݪҼɿ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 158

Slide 158 text

class ExampleViewController: UIViewController { private var actions: ExampleViewsAction? @IBOutlet weak var label: UILabel! override func viewDidLoad() { super.viewDidLoad() self.actions = ExampleViewsAction( label: self.label ) } @IBAction func buttonTapped(_ sender: Any) { self.actions?.buttonDidTapped() } } मਖ਼ޙͷ7JFX$POUSPMMFS ൃ ද Ͱ ͸ ׂ Ѫ

Slide 159

Slide 159 text

class ExampleViewController: UIViewController { private var actions: ExampleViewsAction? @IBOutlet weak var label: UILabel! override func viewDidLoad() { super.viewDidLoad() self.actions = ExampleViewsAction( label: self.label ) } @IBAction func buttonTapped(_ sender: Any) { self.actions?.buttonDidTapped() } } viewDidLoadҎ߱ͷॲཧΛผͷΫϥεʹ੾Γग़͢ ʢͳͥ͜͏͢Δͷ͔͸΋͏গ͠ޙͰΘ͔Γ·͢ʣ ॏཁͳͷ͸ɺviewDidLoadͰॳظԽ͞Εͨ
 UILabelΛ੾Γग़ͨ͠Ϋϥεʹ౉͓ͯ͘͜͠ͱ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 160

Slide 160 text

class ExampleViewController: UIViewController { private var actions: ExampleViewsAction? @IBOutlet weak var label: UILabel! override func viewDidLoad() { super.viewDidLoad() self.actions = ExampleViewsAction( label: self.label ) } @IBAction func buttonTapped(_ sender: Any) { self.actions?.buttonDidTapped() } } Ϙλϯͷλοϓॲཧ͸
 @IBActionΛԣྲྀ͢͠Ε͹0, ൃ ද Ͱ ͸ ׂ Ѫ

Slide 161

Slide 161 text

import UIKit class ExampleViewsAction { private let label: UILabel init(label: UILabel) { self.label = label } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } 7JFX$POUSPMMFS͔Β෼཭͞Εͨίʔυ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 162

Slide 162 text

import UIKit class ExampleViewsAction { private let label: UILabel init(label: UILabel) { self.label = label } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } ஫ɿ͜ͷ໊લ͸ద౰ͳͷͰɺ࣮ࡍ͸֤ʑͷ
 ΞʔΩςΫνϟʹԊ໋໊ͬͨʹ͍ͯͩ͘͠͞ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 163

Slide 163 text

import UIKit class ExampleViewsAction { private let label: UILabel init(label: UILabel) { self.label = label } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } 7JFX$POUSPMMFS͔Β౉͞ΕͨUILabel ൃ ද Ͱ ͸ ׂ Ѫ

Slide 164

Slide 164 text

import UIKit class ExampleViewsAction { private let label: UILabel init(label: UILabel) { self.label = label } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } 7JFX$POUSPMMFSͷॲཧΛͦͷ··Ҡಈ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 165

Slide 165 text

import UIKit class ExampleViewsAction { private let label: UILabel init(label: UILabel) { self.label = label } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } self.present͕ଘࡏ͠ͳ͍ ʢ͜Ε͸গ͠ޙͰमਖ਼͢Δʣ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 166

Slide 166 text

मਖ਼ޙͷಈ࡞֬ೝίʔυ import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let label = UILabel() let actions = ExampleViewsAction(label: label) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } ൃ ද Ͱ ͸ ׂ Ѫ

Slide 167

Slide 167 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let label = UILabel() let actions = ExampleViewsAction(label: label) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } 7JFX$POUSPMMFSͰ͸ͳ͘ɺ
 ੾Γग़ͨ͠ΫϥεͷํΛ
 ಈ࡞֬ೝ͢ΔΑ͏ʹ͢Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 168

Slide 168 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let label = UILabel() let actions = ExampleViewsAction(label: label) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } 7JFX$POUSPMMFS͔ΒUILabel͕౉͞ΕΔͷΛ࠶ݱ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 169

Slide 169 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let label = UILabel() let actions = ExampleViewsAction(label: label) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } @IBActionͰλοϓΛ࠶ݱ͢Δ෦෼͸ ੾Γग़ͨ͠Ϋϥεͷํͷϝιουͷ࣮ߦͰ୅ସ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 170

Slide 170 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let label = UILabel() let actions = ExampleViewsAction(label: label) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } ઌ΄Ͳ౉ͨ͠UILabelͷ಺༰͕
 มΘ͍ͬͯΔ͔͔֬ΊΒΕ͍ͯΔ ͜͏͢Δ͜ͱͰUILabel͕·ͩ
 ଘࡏ͠ͳ͍໰୊ΛղܾͰ͖Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 171

Slide 171 text

import UIKit class ExampleViewsAction { private let label: UILabel init(label: UILabel) { self.label = label } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } self.present͕ଘࡏ͠ͳ͍ͷͰ
 ·ͩϏϧυ͕௨Βͳ͍ 7JFX$POUSPMMFS͔Β෼཭͞Εͨίʔυ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 172

Slide 172 text

import UIKit class ModalPresenter { private weak var viewController: UIViewController? init(willPresentOn viewController: UIViewController) { self.viewController = viewController } func present(_ viewController: UIViewController, animated: Bool) { self.viewController?.present(viewController, animated: animated) } } self.present͕ଘࡏ͠ͳ͍໰୊ͷղܾ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 173

Slide 173 text

import UIKit class ModalPresenter { private weak var viewController: UIViewController? init(willPresentOn viewController: UIViewController) { self.viewController = viewController } func present(_ viewController: UIViewController, animated: Bool) { self.viewController?.present(viewController, animated: animated) } } 7JFX$POUSPMMFSͷpresentΛ
 ผͷΫϥεͰ΋ୟ͚ΔΑ͏ʹ͢ΔΫϥε ൃ ද Ͱ ͸ ׂ Ѫ

Slide 174

Slide 174 text

import UIKit class ModalPresenter { private weak var viewController: UIViewController? init(willPresentOn viewController: UIViewController) { self.viewController = viewController } func present(_ viewController: UIViewController, animated: Bool) { self.viewController?.present(viewController, animated: animated) } } presentʹ࢖͏7JFX$POUSPMMFSΛ಺෦ʹอ࣋͢Δ
 ʢϝϞϦϦʔΫΛආ͚ΔͨΊʹweakʹ͢Δʣ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 175

Slide 175 text

import UIKit class ModalPresenter { private weak var viewController: UIViewController? init(willPresentOn viewController: UIViewController) { self.viewController = viewController } func present(_ viewController: UIViewController, animated: Bool) { self.viewController?.present(viewController, animated: animated) } } ͜ͷΫϥεͷpresentΛ࣮ߦ͢Δͱɺอ͍࣋ͯͨ͠
 7JFX$POUSPMMFSͷpresent͕࣮ߦ͞ΕΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 176

Slide 176 text

import UIKit class ExampleViewsAction { private let label: UILabel private let modalPresenter: ModalPresenter init(label: UILabel, modalPresenter: ModalPresenter) { self.label = label self.modalPresenter = modalPresenter } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.modalPresenter.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } मਖ਼ޙͷ7JFX$POUSPMMFS͔Β෼཭͞Εͨίʔυ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 177

Slide 177 text

import UIKit class ExampleViewsAction { private let label: UILabel private let modalPresenter: ModalPresenter init(label: UILabel, modalPresenter: ModalPresenter) { self.label = label self.modalPresenter = modalPresenter } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.modalPresenter.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } 7JFX$POUSPMMFS͔ΒUILabelͱҰॹʹ
 ઌ΄ͲͷModalPresenterΛड͚औΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 178

Slide 178 text

import UIKit class ExampleViewsAction { private let label: UILabel private let modalPresenter: ModalPresenter init(label: UILabel, modalPresenter: ModalPresenter) { self.label = label self.modalPresenter = modalPresenter } func buttonDidTapped() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, error) in guard let `self` = self else { return } if let error = error { // লུ self.modalPresenter.present(alertViewController, animated: true) return } self.label.text = "Hello, \(user!.name)!" } } } self.presentΛModalPresenterͷ
 presentͷݺͼग़͠΁ม͑Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 179

Slide 179 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter( willPresentOn: UIViewController() ) let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter ) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } मਖ਼ޙͷಈ࡞֬ೝίʔυ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 180

Slide 180 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter( willPresentOn: UIViewController() ) let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter ) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } Ϗϧυ͕௨Γ͑͢͞Ε͹͍͍ͷͰɺ
 ద౰ͳModalPresenterΛ࡞੒͢Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 181

Slide 181 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter( willPresentOn: UIViewController() ) let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter ) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } 7JFX$POUSPMMFS͔Β
 ੾Γग़ͨ͠Ϋϥε΁౉͢ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 182

Slide 182 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter( willPresentOn: UIViewController() ) let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter ) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } Ϗϧυ͕௨ΔΑ͏ʹͳͬͨ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 183

Slide 183 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter( willPresentOn: UIViewController() ) let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter ) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } XCTAssertEqual failed: ("nil") is
 not equal to ("Optional(true)") ൃ ද Ͱ ͸ ׂ Ѫ

Slide 184

Slide 184 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter( willPresentOn: UIViewController() ) let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter ) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } ͜ͷ࣌ͷlabel.textΛݟΔͱ
 ॳظ஋ͷ··ʹͳ͍ͬͯͨ Ϣʔβʔ໊͕·ͩදࣔ͞Ε͍ͯͳ͍Α͏ͩ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 185

Slide 185 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter( willPresentOn: UIViewController() ) let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter ) actions.buttonDidTapped() XCTAssertTrue(label.text?.contains("Kuniwak")) } } ݪҼɿ αʔόʔ͔Βͷฦ৴͕·ͩ
 ฦ͖͍ͬͯͯͳ͍ͷͰɺ
 UILabelΛߋ৽Ͱ͖͍ͯͳ͍ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 186

Slide 186 text

Ұൠతʹɺ"1*͕ฦ͖ͬͯͨޙͷ7JFXͷ
 ߋ৽ͷ׬ྃΛݕ஌͢Δͷ͸೉͍͠ ྫ͑͹ɺ࣍ͷίʔυͰ7JFXͷߋ৽͕
 ׬ྃ͢Δͷ͸"ͱ#ͷͲͪΒʁ if isAdminMode { callAdminAPI { [weak self] (admin, error) in guard let `self` = self else { return } self.label.color = admin != nil ? .red : .blue } } callUserAPI { [weak self] (user, error) in guard let `self` = self else { return } self.label.text = user.name } " # ൃ ද Ͱ ͸ ׂ Ѫ

Slide 187

Slide 187 text

ਖ਼ղ͸ɺʮ"ͱ#ͷͲͪΒ΋͋Γ͑Δʯ ͭͷ"1*ͷฦͬͯ͘ΔλΠϛϯάʹΑͬͯ
 "ͷͱ͖΋͋Ε͹#ͷͱ͖΋͋Δ if isAdminMode { callAdminAPI { [weak self] (admin, error) in guard let `self` = self else { return } self.label.color = admin != nil ? .red : .blue } } callUserAPI { [weak self] (user, error) in guard let `self` = self else { return } self.label.text = user.name } callAdminAPI͕
 ޙʹ׬ྃ͢Ε͹" callUserAPI͕
 ޙʹ׬ྃ͢Ε͹# ൃ ද Ͱ ͸ ׂ Ѫ

Slide 188

Slide 188 text

ݟͨ໨ͷߋ৽Λ"1*ͳͲͷཪଆͷࣄ৘͔Β੾Γ཭͢ͱղܾͰ͖Δ ݟͨ໨Λ࢘ΔίϯϙʔωϯτʹදࣔΛ
 ҰׅͰ൓ө͢Δ͚ͩͷϝιουΛੜ΍͢ "1*ݺͼग़͠౳Ͱ͢΂ͯͷ৘ใ͕ἧͬͨΒ
 ϝιουΛݺͼग़͢ઃܭن໿ʹ͢Δ ͜͏͍͏ͱ͖͸ func apply(userName: String, isAdmin: Bool) { self.label.text = userName self.label.backgroundColor = isAdmin ? .red : .black } // API ͷ྆ํ͕ฦ͖͔ͬͯͯΒදࣔΛ൓ө͢Δ myView.apply(userName: "Kuniwak", isAdmin: false) ൃ ද Ͱ ͸ ׂ Ѫ

Slide 189

Slide 189 text

ݟͨ໨ͱཪଆͷ෼཭ͷͨΊͷ४උ protocol ExampleModelDelegate: class { func apply(state: ExampleModelState) } enum ExampleModelState: Equatable { case success(userName: String) case failure(error: ExampleModelUpdateError) } enum ExampleModelUpdateError: Error, Equatable { case unspecified(debugInfo: String) } ൃ ද Ͱ ͸ ׂ Ѫ

Slide 190

Slide 190 text

protocol ExampleModelDelegate: class { func apply(state: ExampleModelState) } enum ExampleModelState: Equatable { case success(userName: String) case failure(error: ExampleModelUpdateError) } enum ExampleModelUpdateError: Error, Equatable { case unspecified(debugInfo: String) } ཪଆͷ࢓ࣄͷ४උ͕੔ͬͨͱ͖ʹୟ͍ͯ΋Β͏
 ݟͨ໨ͷҰׅ൓өϝιου ൃ ද Ͱ ͸ ׂ Ѫ

Slide 191

Slide 191 text

protocol ExampleModelDelegate: class { func apply(state: ExampleModelState) } enum ExampleModelState: Equatable { case success(userName: String) case failure(error: ExampleModelUpdateError) } enum ExampleModelUpdateError: Error, Equatable { case unspecified(debugInfo: String) } ཪଆͷ࠷ऴతͳ݁Ռ͸ɺ w ੒ޭͯ͠userName w ࣦഊͯ͠error ͷͲͪΒ͔ͳͷͰɺFOVNͰදݱ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 192

Slide 192 text

protocol ExampleModelDelegate: class { func apply(state: ExampleModelState) } enum ExampleModelState: Equatable { case success(userName: String) case failure(error: ExampleModelUpdateError) } enum ExampleModelUpdateError: Error, Equatable { case unspecified(debugInfo: String) } ཪଆͷ࢓ࣄͷ݁Ռ͕Equatableͩͱ
 ޙͰศརʹͳΔͷͰɺEquatableͳ
 ΤϥʔͷܕΛ࡞੒͓ͯ͘͠ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 193

Slide 193 text

ཪଆͷ࢓ࣄΛ͓͜ͳ͏Ϋϥε class ExampleModel { weak var delegate: ExampleModelDelegate? func update() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, erro guard let `self` = self else { return } if let error = error { self.delegate?.apply(state: .failure(error: .unspecified(debugInfo: "\(error)") } else if let user = user { self.delegate?.apply(state: .success(userName: user.name)) } } } } ൃ ද Ͱ ͸ ׂ Ѫ

Slide 194

Slide 194 text

class ExampleModel { weak var delegate: ExampleModelDelegate? func update() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, erro guard let `self` = self else { return } if let error = error { self.delegate?.apply(state: .failure(error: .unspecified(debugInfo: "\(error)") } else if let user = user { self.delegate?.apply(state: .success(userName: user.name)) } } } } ஫ɿ͜ͷ໊લ͸ద౰ͳͷͰɺ࣮ࡍ͸֤ʑͷ
 ΞʔΩςΫνϟʹԊ໋໊ͬͨʹ͍ͯͩ͘͠͞ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 195

Slide 195 text

class ExampleModel { weak var delegate: ExampleModelDelegate? func update() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, erro guard let `self` = self else { return } if let error = error { self.delegate?.apply(state: .failure(error: .unspecified(debugInfo: "\(error)") } else if let user = user { self.delegate?.apply(state: .success(userName: user.name)) } } } } ཪଆͷ४උ͕੔ͬͨΒ௨஌͢Δઌͷ%FMFHBUF ͜ͷྫͰ͸ɺ7JFX$POUSPMMFS͔Β੾Γग़ͨ͠
 Ϋϥε͕͜ͷ%FMFHBUFΛ࣮૷͢Δ͜ͱʹͳΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 196

Slide 196 text

class ExampleModel { weak var delegate: ExampleModelDelegate? func update() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, erro guard let `self` = self else { return } if let error = error { self.delegate?.apply(state: .failure(error: .unspecified(debugInfo: "\(error)") } else if let user = user { self.delegate?.apply(state: .success(userName: user.name)) } } } } "1*ͷݺͼग़͠͸ɺ͜ͷΫϥεͷ
 updateϝιουͷ࣮ߦͰ͸͡ΊΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 197

Slide 197 text

class ExampleModel { weak var delegate: ExampleModelDelegate? func update() { APIClient.shared.get(type: User.self, url: URLs.getSomething) { [weak self] (user, erro guard let `self` = self else { return } if let error = error { self.delegate?.apply(state: .failure(error: .unspecified(debugInfo: "\(error)") } else if let user = user { self.delegate?.apply(state: .success(userName: user.name)) } } } } "1*ͷ݁Ռ͕ࣦഊͷΑ͏ͳΒ.failure Λ %FMFHBUF΁௨஌͠ɺ੒ޭ͍ͯ͠ΔΑ͏
 ͳΒ .successΛ%FMFHBUF΁௨஌͢Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 198

Slide 198 text

7JFX$POUSPMMFS͔Β෼཭ͨ͠ΫϥεͷFYUFOTJPO extension ExampleViewsAction: ExampleModelDelegate { func apply(state: ExampleModelState) { switch state { case .failure(let error): dump(error) let alertViewController = UIAlertController( title: "Τϥʔ͕ൃੜ͠·ͨ͠", message: nil, preferredStyle: .alert ) alertViewController.addAction(UIAlertAction(title: "OK", style: .default)) self.modalPresenter.present(alertViewController, animated: true) case .success(let userName): self.label.text = "Hello, \(userName)!" } } } ൃ ද Ͱ ͸ ׂ Ѫ

Slide 199

Slide 199 text

extension ExampleViewsAction: ExampleModelDelegate { func apply(state: ExampleModelState) { switch state { case .failure(let error): dump(error) let alertViewController = UIAlertController( title: "Τϥʔ͕ൃੜ͠·ͨ͠", message: nil, preferredStyle: .alert ) alertViewController.addAction(UIAlertAction(title: "OK", style: .default)) self.modalPresenter.present(alertViewController, animated: true) case .success(let userName): self.label.text = "Hello, \(userName)!" } } } ઌ΄Ͳͷ%FMFHBUFΛ࣮૷ͤ͞Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 200

Slide 200 text

extension ExampleViewsAction: ExampleModelDelegate { func apply(state: ExampleModelState) { switch state { case .failure(let error): dump(error) let alertViewController = UIAlertController( title: "Τϥʔ͕ൃੜ͠·ͨ͠", message: nil, preferredStyle: .alert ) alertViewController.addAction(UIAlertAction(title: "OK", style: .default)) self.modalPresenter.present(alertViewController, animated: true) case .success(let userName): self.label.text = "Hello, \(userName)!" } } } දࣔͷҰׅߋ৽ϝιουΛ࣮૷
 ʢ಺༰͸मਖ਼લͱಉ͡ʣ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 201

Slide 201 text

class ExampleViewsAction { private let label: UILabel private let modalPresenter: ModalPresenter private let model: ExampleModel init(label: UILabel, modalPresenter: ModalPresenter, model: ExampleModel) { self.label = label self.modalPresenter = modalPresenter self.model = model } func buttonDidTapped() { self.model.update() } } 7JFX$POUSPMMFS͔Β෼཭ͨ͠Ϋϥε ൃ ද Ͱ ͸ ׂ Ѫ

Slide 202

Slide 202 text

class ExampleViewsAction { private let label: UILabel private let modalPresenter: ModalPresenter private let model: ExampleModel init(label: UILabel, modalPresenter: ModalPresenter, model: ExampleModel) { self.label = label self.modalPresenter = modalPresenter self.model = model } func buttonDidTapped() { self.model.update() } } ཪଆͷ࢓ࣄΫϥεͷ࡞੒Λ͜ͷதͰ΍ͬͯ΋͍͍ ͕ɺ7JFX$POUSPMMFS͔Β౉ͯ͠΋Β͏ͱɺͷͪ ͷָͪʹͳΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 203

Slide 203 text

class ExampleViewsAction { private let label: UILabel private let modalPresenter: ModalPresenter private let model: ExampleModel init(label: UILabel, modalPresenter: ModalPresenter, model: ExampleModel) { self.label = label self.modalPresenter = modalPresenter self.model = model } func buttonDidTapped() { self.model.update() } } ϘλϯͷλοϓͰཪଆͷ࢓ࣄΛ࢝ΊΔ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 204

Slide 204 text

मਖ਼ޙͷ7JFX$POUSPMMFS import UIKit class ExampleViewController: UIViewController { // লུ override func viewDidLoad() { super.viewDidLoad() self.actions = ExampleViewsAction( label: self.label, modalPresenter: ModalPresenter(willPresentOn: self), model: ExampleModel() ) } } ൃ ද Ͱ ͸ ׂ Ѫ

Slide 205

Slide 205 text

import UIKit class ExampleViewController: UIViewController { // লུ override func viewDidLoad() { super.viewDidLoad() self.actions = ExampleViewsAction( label: self.label, modalPresenter: ModalPresenter(willPresentOn: self), model: ExampleModel() ) } } UILabelͳͲΛ౉͍ͭ͢Ͱʹཪଆͷ
 ࢓ࣄΫϥε΋࡞੒ͯ͠౉͓ͯ͘͠ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 206

Slide 206 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } मਖ਼ޙͷಈ࡞֬ೝίʔυ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 207

Slide 207 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } Ϙλϯͷλοϓͷ࠶ݱͰ͸ͳ͘ɺ
 ௚઀ݟͨ໨ͷ൓өϝιουΛୟ͘ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 208

Slide 208 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } ͔͠͠ɺ͜͏ͯ͠͠·͏ͱϘλϯΛλοϓͯ͠
 ද͕ࣔߋ৽͞ΕΔ͜ͱͷ֬ೝʹͳΒͳ͍ͷͰ͸ʁ
 ͱ͍͏ෆ҆͸࣍ͷͭͷํ๏Ͱ؇࿨Ͱ͖Δɿ w Ϙλϯ͕λοϓ͞ΕͨΒɺཪͷ࢓ࣄΫϥε͕
 ݺ͹ΕΔ͜ͱΛ֬ೝ͢ΔίʔυΛ௥Ճ w ཪͷ࢓ࣄΫϥε͕ݺ͹ΕͨΒɺඞͣ׬ྃ͢Δ
 ͜ͱΛ֬ೝ͢ΔίʔυΛ௥Ճ ͦΕͧΕͷৄࡉ͸εϥΠυͷຕ਺ͷࣄ৘ͰׂѪ͢Δ͕ɺ Ҏ߱ͷεϥΠυͷ஌͚ࣝͩͰ࣮૷Ͱ͖Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 209

Slide 209 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } Ͱ͸ಈ࡞֬ೝΛ࣮ߦͯ͠ΈΑ͏ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 210

Slide 210 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } ͜͜·Ͱ͖ͯ΍ͬͱ੒ޭ͠·͢ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 211

Slide 211 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } ͔͠͠ɺ·ͩ"1*ݺͼग़͕͠Τϥʔʹ ͳͬͨ৔߹ͷಈ࡞֬ೝΛͰ͖͍ͯͳ͍ʜ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 212

Slide 212 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } ͜Ε΋ίʔυͰಈ࡞֬ೝͰ͖Δ͕ɺ
 εϥΠυͷຕ਺ͷ౎߹ͰׂѪ͢Δ ͜ͷ࡞ۀͷώϯτΛॻ͍͓ͯ͘ɿ w "1*ͷ݁ՌΛಈ࡞֬ೝίʔυ͔Β
 ࢦఆͰ͖ΔΑ͏ʹ͢Δ ‎ *OQVU0CKFDU*OKFDUJPO w .PEBM1SFTFOUFSͷϝιουݺͼग़͠Λ
 ه࿥͢ΔِͷΦϒδΣΫτΛ࡞੒͢Δ ‎ 0VUQVU0CKFDU*OKFDUJPO ͦΕͧΕͷৄࡉ͸ɺεϥΠυͷޙํͰ
 ঺հ͢ΔʮJ04Ͱςετ༰қͳઃܭΛ
 ࣮ݱ͢ΔͨΊͷσβΠϯύλʔϯʯͰ
 αϯϓϧίʔυͱ߹Θͤͯղઆ͍ͯ͠Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 213

Slide 213 text

import XCTest import UIKit @testable import IOSDC2018Debugging class ExampleViewControllerTest: XCTestCase { func testMyNameIsVisible() { let dummyModalPresenter = ModalPresenter(willPresentOn: UIViewControlle let label = UILabel() let actions = ExampleViewsAction( label: label, modalPresenter: dummyModalPresenter, model: ExampleModel() ) actions.apply(state: .success(userName: "Kuniwak")) XCTAssertTrue(label.text?.contains("Kuniwak")) } } ͜Ε·Ͱͷ࡞ۀͰ΍ͬͨ͜ͱɿ w 7JFX$POUSPMMFSͷॲཧΛผ΁੾Γग़ͨ͠ w ผͷΫϥεͰUIViewController.presentΛ
 ࢖͑ΔΑ͏ʹͨ͠ w ݟͨ໨ͷҰׅ൓өΛίʔυ͔Β
 ࣮ߦͰ͖ΔΑ͏ʹͨ͠ ࣗಈͰͷಈ࡞֬ೝʹඞཁͳࡉ͔ͳ஌͕ࣝ
 ͱͯ΋ଟ͍͜ͱ͕Θ͔Δ ൃ ද Ͱ ͸ ׂ Ѫ

Slide 214

Slide 214 text

ಈ࡞֬ೝͷࣗಈԽʹ͸ɺී௨ͷ
 ΞϓϦ࣮૷ͱ͸ҟͳΔ஌͕ࣝඞཁ ݴ͍͔ͨͬͨ͜ͱ͸

Slide 215

Slide 215 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ

Slide 216

Slide 216 text

։ൃ଎౓ͷ૿Ճྔ ͜͜·Ͱ͸͢ΜͳΓ͍͘ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ

Slide 217

Slide 217 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ͋ΕʁࣗಈԽ͕೉͍ͧ͠ʜʁ
 Ͱ΋ηϧϑνΣοΫͪΌΜͱ
 ΍ͬͯΔ͔Β͕͔͔࣌ؒΔʜ

Slide 218

Slide 218 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ΋͏ͪΐͬͱؤுͬͯΈ͚ͨͲɺ
 ͕͔͔࣌ؒΓ͗͢Δʜʜ

Slide 219

Slide 219 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ͩΊͩɺࣗಈԽແཧͩʜ ͜Μͳঢ়گͰෆ҆ͳൣғ
 ͢΂ͯͷ֬ೝͳΜͯແཧʜ

Slide 220

Slide 220 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ΋͠ɺޮ཰తʹಈ࡞֬ೝΛ
 ࣗಈԽ͢ΔͨΊͷ஌ࣝΛ
 ͍࣋ͬͯͨΒʜ

Slide 221

Slide 221 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ΋͏ͪΐͬͱؤுͬͯΈ͚ͨͲɺ
 ͕͔͔࣌ؒΓ͗͢Δʜʜ

Slide 222

Slide 222 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ͕͔͔͍࣌ؒͬͯΔͷ͸ɺ
 ͜ͷςΫχοΫ࢖͑͹
 গ͠ϚγʹͳΔ͸ͣʜ

Slide 223

Slide 223 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ͋ɺͳΜָ͔ʹͳ͖ͬͯͨ

Slide 224

Slide 224 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ΊͬͪΌָʹͳͬͨ

Slide 225

Slide 225 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ͋ͱ͔ΒৼΓฦΔͱɺ
 ͜͜ʹͭΒ͍࣌ظ͕͋ͬͨ

Slide 226

Slide 226 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ࣗಈԽͷ୩

Slide 227

Slide 227 text

։ൃ଎౓ͷ૿Ճྔ ࣌ؒܦա --%#ͷ
 ׆༻ มߋ௚ޙͷ
 σόοά ෆ҆ۦಈ
 νΣοΫ ಈ࡞֬ೝͷ
 ࣗಈԽ ؒҧ͑ʹ͍͘
 ઃܭ ࣗಈԽͷ୩Λӽ͑ΔͨΊʹ͸ɺ
 ͏·͘੾Γൈ͚ΔͨΊͷ஌͕ࣝ
 ͱͯ΋େࣄͩͱ͍͏͜ͱ

Slide 228

Slide 228 text

ࢲͷྫͰ͸ɺݩ͔Βಈ࡞֬ೝΛ
 ಘҙͱ͍ͯͨ͠,VOJXBL͕ओಋͨ͠ ͭ·Γɺ୩Λ৐Γӽ͑Δ஌ࣝΛ΋͍ͬͯͯ
 ڧͯ͘χϡʔήʔϜʹͳ͍ͬͯΔ

Slide 229

Slide 229 text

ࣗಈԽͷ୩Λʮ͍ͭʯ
 ৐Γӽ͑Δ͔ ܦݧऀ͕ޠΔ

Slide 230

Slide 230 text

ίʔυ͕ߴྸͳ΄ͲɺࣗಈԽͷ୩͸
 Ͳ͜·Ͱ΋ਂ͘ͳΓɺ͔ͭ௕͘ͳΔ ߴྸͳίʔυͰ͍͖ͳΓࣗಈԽͷ୩ӽ͑Λ
 ໨ࢦ͢ͷ͸ແ஡Λӽ͑ͯແ๳ ٯʹɺίʔυ͕ए͚Ε͹·ͩࣗಈԽͷ୩Λ
 ӽ͑ΒΕΔνϟϯε͕͋Δ ࢲͷࣄྫͰ͸ϑϧεΫϥονʹ
 ్த͔ΒࢀՃͯ࢝͠Ί͍ͯΔ

Slide 231

Slide 231 text

৽ػೳ࣮૷΍ϦχϡʔΞϧͳͲͰ
 ৽͍͠ίʔυΛ͜Ε͔Βॻ͘ਓ͸ɺ ࠓ͕νϟϯεͩʂ

Slide 232

Slide 232 text

୩ΛҰ౓Ͱ΋ӽ͑ΔܦݧΛͨ͠ਓ͸
 ͔࣍Βڧͯ͘χϡʔήʔϜͰ͖Δ िؒͰ΋͍͍ͷͰɺখ͍͞࿅श༻ΞϓϦͰ
 ࣗಈԽΛମݧ͓ͯ͘͜͠ͱ͕Φεεϝ ࠓλΠϛϯά͕ѱͯ͘΋ ࢲͷࣗಈԽͷ࿅शΞϓϦ HJUIVCDPN,VOJXBL5FTUBCMF%FTJHO&YBNQMF

Slide 233

Slide 233 text

ࣗಈԽͷ୩ΛʮͲ͏ʯ
 ৐Γӽ͑Δ͔ ܦݧऀ͕ޠΔ

Slide 234

Slide 234 text

ࣗಈԽͷ୩Λ౿ഁ͢ΔͨΊʹ͸ɺҎԼͷ
 ஌͕ࣝ໾ʹཱͭɿ w ޮ཰తͳಈ࡞֬ೝίʔυͷॻ͖ํ w ಈ࡞֬ೝ͠΍͍͢ຊମΞϓϦͷॻ͖ํ w ຊମΞϓϦͷม͍͖͑ͯํ ͜ΕΒͷτϐοΫ͸ʮςετʯͱ͍͏
 ΧςΰϦͰޠΒΕΔ͜ͱ͕ଟ͍Ͱ͢

Slide 235

Slide 235 text

ࣗಈԽͷ୩ӽ͑ͷͨΊͷࢿྉ ྫ͑͹ʜ

Slide 236

Slide 236 text

ʮJ04Ͱςετ༰қͳઃܭΛ
 ࣮ݱ͢ΔͨΊͷσβΠϯύλʔϯʯ https://speakerdeck.com/orgachem/ios-detesutorong- yi-nashe-ji-wo-shi-xian-surutamefalsedezainpatan ൃ ද Ͱ ͸ ׂ Ѫ

Slide 237

Slide 237 text

ʮ4XJGUͷ)551ϥΠϒϥϦͰۤ͠·ͳ͍ͨΊͷ
 ࣗ࡞"1*ΫϥΠΞϯτઃܭʯ https://qiita.com/Kuniwak/items/a972ff2ade643799d1fe ൃ ද Ͱ ͸ ׂ Ѫ

Slide 238

Slide 238 text

ʮ4XJGUͰॻ͍͓ͯ΅͑Δ5%%ʯ μϯϘʔాத / @ktanaka117 ฤ ஶ
 https://danbo-house.booth.pm/items/837289 ൃ ද Ͱ ͸ ׂ Ѫ

Slide 239

Slide 239 text

ಠֶͷݶքΛײͨ͡Β ͍͔ͭ๚ΕΔ

Slide 240

Slide 240 text

ʮJ045FTU/JHIUʯ https://testnight.connpass.com/ PS݄ʹ౦ژͰ։࠵༧ఆ

Slide 241

Slide 241 text

%JTDPSETXJGUEFWFMPQFSTKBQBOUFTUJOH https://discordapp.com/invite/4Scjz4J ΦϯϥΠϯνϟοτͰ΋૬ஊͰ͖Δ৔ॴ͕͋Δ

Slide 242

Slide 242 text

͜ͷൃදͰ఻͖͑Εͳ͔ͬͨ
 ৄࡉͳ࣮૷ύλʔϯʹ͍ͭͯ͸ʜ ͦͯ͠ʜ

Slide 243

Slide 243 text

ຊΛॻ͖·͢

Slide 244

Slide 244 text

ٕज़ॻΫϥ΢υϑΝϯσΟϯά1&",4Ͱ
 ϓϩδΣΫτΛެ։༧ఆʢ݄ʣ https://peaks.cc $0. */(
 400/

Slide 245

Slide 245 text

୩ӽ͑ͷ৺ߏ͑ λΠϛϯά͕੔ͬͨͱ͖ͷ

Slide 246

Slide 246 text

λΠϛϯά͕ສશͰ΋
 ୩͸ඞͣଘࡏ͢Δ ୩ఈʹԿ͕જΈɺ
 Ͳ͏৐Γӽ͑Δ͔Λ஌Ζ͏

Slide 247

Slide 247 text

৐Γӽ͑ΔͨΊͷ஌ࣝ͸ଟ͘ɺ
 ࠷ॳ͸೉͘͠ײ͡Δ͔΋͠Εͳ͍ ͦΕͰ΋ɺ֮ͭ͑Δ͝ͱʹ
 ୩͔Β͸গͮͭ͠཭Ε͍ͯΔ

Slide 248

Slide 248 text

ཱͪࢭ·ͬͯ΋
 ݱࡏ஍͸มΘΒͳ͍ ਐΊΔ࣌ʹਐΉ͙Β͍Ͱ
 ͪΐ͏Ͳ͍͍

Slide 249

Slide 249 text

·ͱΊ ΁ͷ։ൃ଎౓޲্Λࢧ͑ͨ ͭͷϊ΢ϋ΢ɿ --%#Λ࢖͍͜ͳ͢ σόοάͷλΠϛϯάΛมߋ௚ޙʹ͢Δ ෆ҆ۦಈͰηϧϑνΣοΫ͢Δ ಈ࡞֬ೝΛࣗಈԽ͢Δ ؒҧ͍ʹ͍͘ઃܭʹ͢Δ

Slide 250

Slide 250 text

,VOJXBL͔Βͷϝοηʔδ ։ൃ଎౓ୡ੒ͷલʹ͸
 ࣗಈԽͷ୩͕ଘࡏ͢Δ ৐Γӽ͑ΔͨΊͷ஌ࣝΛ
 ͍֮ͭͣͭ͑ͯ͜͏ ཱͪࢭ·ͬͯ΋ޙ໭Γ͸͠ͳ͍͔Βɺ
 ਐΊΔ࣌ʹਐΉ͙Β͍Ͱͪΐ͏Ͳ͍͍

Slide 251

Slide 251 text

ݸਓతʹ͸ɺJ04%$Ͱ΋΋ͬͱ
 ࣗಈతͳಈ࡞֬ೝʢςετʣͷ
 ϊ΢ϋ΢ͷൃද͕͋ͬͯ΋͍͍ͱࢥ͏ʜ