Slide 1

Slide 1 text

αϙʔτޮ཰Λ্͛ΔͨΊͷ ϩΪϯά؀ڥߏங 2017/09/17 (೔) ງݟ फҰ࿠ @horimislime iOSDC Japan 2017

Slide 2

Slide 2 text

ࣗݾ঺հ • ງݟ फҰ࿠ (@horimislime) • ! גࣜձࣾτϨλ • " iPad޲͚ͷ༧໿୆ாΞϓϦ։ൃ • # ϞόΠϧΞϓϦͷΤϥʔϩάऩूʹ͍ͭͯ iOSDC Japan 2017

Slide 3

Slide 3 text

ฐࣾʹ͍ͭͯ • 2013೥ϩʔϯνɺࠃ಺8000ళͰಋೖ • ଟݴޠԽͰΞδΞݍʹ΋ల։ ! • ࠷ۙ͸BLEΛ࢖ͬͨϋʔυ΢ΣΞ΋ iOSDC Japan 2017

Slide 4

Slide 4 text

Կ͕ى͖͔ͨ • ࠶ݱੑͷͳ͍ෆ۩߹໰͍߹Θ͕ͤ • ίϛϡχέʔγϣϯίετͷ૿େ • ϋʔυ΢ΣΞ΋བྷΜͰ͞ΒʹෳࡶԽ iOSDC Japan 2017

Slide 5

Slide 5 text

Ξϓϩʔν 1. ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ 2. ௐࠪʹඞཁͳώϯτ͸ͳΔ΂͘૿΍͢ 3. ໰͍߹Θͤ࣌ͷίετΛݮΒ͢ iOSDC Japan 2017

Slide 6

Slide 6 text

Ξϓϩʔν 1. ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ 2. ௐࠪʹඞཁͳώϯτ͸ͳΔ΂͘૿΍͢ 3. ໰͍߹Θͤ࣌ͷίετΛݮΒ͢ iOSDC Japan 2017

Slide 7

Slide 7 text

ฐࣾͷ͜Ε·Ͱ • HockeyAppͰΫϥογϡऩूʢ഑෍͸ݱ໾ʣ • Ϋϥογϡ৘ใҎ֎ʹϩάϑΝΠϧͷૹ৴ػೳ • ϩάૹ৴ͷλΠϛϯά͸Ϋϥογϡ࣌ͷΈ • Ϋϥογϡ࣌ͷ৘ใ͕গͳ͍ iOSDC Japan 2017

Slide 8

Slide 8 text

Ҡߦܭը • ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ • ΫϥογϡɾΤϥʔૹ৴࣌ͷঢ়ଶΛৄ͘͠஌Γ͍ͨ • BugsnagΛ࠾༻͢Δࣄʹ iOSDC Japan 2017

Slide 9

Slide 9 text

αʔϏεબఆ • େखͩͱ3αʔϏε͕΄΅ಉ౳ͷػೳ • • • • ʮύϯͣ͘ϩάʯΛ࢖͑Δͷ͕ศར iOSDC Japan 2017

Slide 10

Slide 10 text

ύϯͣ͘ϩά • Τϥʔൃੜ·Ͱͷಓ͠Δ΂ • ΞϓϦͷ৭Μͳॴʹ࢓ࠐΉ͚ͩ • ΤϥʔͱҰॹʹ࣌ܥྻͰϩάදࣔ func buttonTapped(sender: UIButton) { Bugsnag.leaveBreadcrumb("\(sender.title) tapped!") } iOSDC Japan 2017

Slide 11

Slide 11 text

Logger.swift struct Logger { func info(message: String) { debugPrint(message) Bugsnag.leaveBreadcrumb(message) } func error(message: String) { debugPrint(message) Bugsnag.notifyError(...) } } iOSDC Japan 2017

Slide 12

Slide 12 text

࣮͸iOSඪ४ػೳͱͯ͠΋ଘࡏ iOSDC Japan 2017

Slide 13

Slide 13 text

Activity Tracing iOSDC Japan 2017

Slide 14

Slide 14 text

1. ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ 2. ௐࠪʹඞཁͳώϯτ͸ͳΔ΂͘૿΍͢ 3. ໰͍߹Θͤ࣌ͷίετΛݮΒ͢ iOSDC Japan 2017

Slide 15

Slide 15 text

1. ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ 2. ௐࠪʹඞཁͳώϯτ͸ͳΔ΂͘૿΍͢ 3. ໰͍߹Θͤ࣌ͷίετΛݮΒ͢ iOSDC Japan 2017

Slide 16

Slide 16 text

ௐ͕ࠪḿΔ৘ใͱ͸ • Ϣʔβ͕Ͳ͏͍ͬͨૢ࡞Λߦ͔ͬͨ • ໰୊͕ىͬͨ͜ͷ͸Ͳ͏͍͏ঢ়ଶɾ؀ڥ͔ iOSDC Japan 2017

Slide 17

Slide 17 text

Ϣʔβͷߦಈϩά • ViewControllerͷભҠϩά • ݩʑHockeyApp࣌୅͔Βऩू • ύϯͣ͘ʹͦͷ··ೖΕΔΑ͏ʹ iOSDC Japan 2017

Slide 18

Slide 18 text

UIͷૢ࡞ཤྺ • UITextFieldͷϑΥʔΧεɾUIButtonͷλοϓ౳ • AnalyticsͰर͍ͬͯΔΠϕϯτͱॏෳ͢Δ͕ • accessibilityIdentifierΛૹ࣮ͬͯ૷Λ࠷খ޻਺ʹ iOSDC Japan 2017

Slide 19

Slide 19 text

Ϣʔβ୺຤ͷঢ়ଶ • ࠷ۙͷαʔϏε͸ࣗಈऩू • Bugsnag΋΄ͱΜͲͷঢ়ଶΛऩू iOSDC Japan 2017

Slide 20

Slide 20 text

ωοτϫʔΫ઀ଓঢ়گ • ReachabilityͷΠϕϯτΛߪಡ • ࣮͸"ϧʔλʹܨ͕͍ͬͯΔ͔"͔͠൑ அ͕͔ͭͳ͍ • Πϯλʔωοτʹग़ΒΕͳ͍৔߹΋ iOSDC Japan 2017

Slide 21

Slide 21 text

ͦͷଞͷίϯιʔϧϩά • γεςϜ͕ు͖ग़ͯ͠Δϩά (AutoLayout่ΕͳͲ) • ϩάอଘઌΛ೚ҙͷσΟϨΫτϦԼʹมߋͰ͖Δ • Ϋϥογϡʹhookͯ͠ϑΝΠϧͷத਎Λૹ৴͢Δ͜ͱ΋Մೳ var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) let directory = paths[0] let logFilePath = (directory as NSString).appendingPathComponent("\(Date()).log") freopen(logFilePath.cString(using: String.Encoding.ascii)!, "a+", stderr) iOSDC Japan 2017

Slide 22

Slide 22 text

1. ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ 2. ௐࠪʹඞཁͳώϯτ͸ͳΔ΂͘૿΍͢ 3. ໰͍߹Θͤ࣌ͷίετΛݮΒ͢ iOSDC Japan 2017

Slide 23

Slide 23 text

1. ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ 2. ௐࠪʹඞཁͳώϯτ͸ͳΔ΂͘૿΍͢ 3. ໰͍߹Θͤ࣌ͷίετΛݮΒ͢ iOSDC Japan 2017

Slide 24

Slide 24 text

໰͍߹Θͤ࣌ͷίετ͸ͳͥ૿͑Δ͔ • ௐࠪʹඞཁͳϩά͕ͦ΋ͦ΋ݟΕͳ͍ • ೔ຊޠͰత֬ʹ఻ୡ͢Δͷ͕೉͍͠ iOSDC Japan 2017

Slide 25

Slide 25 text

struct Service { func connectToDevice(completion: Result) { // ॲཧ if notReady { completion(.failure(NSError(domain: "in.toreta", code: 0, userInfo: nil))) } else { completion(.success(response)) } } } override func viewDidLoad() { super.viewDidLoad() service.connectToDevice { result in switch result { case .success(let data): ... case .failure(let _): HUD.show("Τϥʔ͕ൃੜ͠·ͨ͠ɻ઀ଓ؀ڥΛ֬ೝ͍ͩ͘͞ɻ") } } } iOSDC Japan 2017

Slide 26

Slide 26 text

ϩδοΫΤϥʔ΋ৄࡉʹྻڍ enum ApplicationError: Error { case bleNotAvailable case hardwareNotReady ... } struct Service { func connectToDevice(completion: Result) { // ॲཧ if notReady { completion(.failure(.hardwareNotReady)) } else { completion(.success(response)) } } } iOSDC Japan 2017

Slide 27

Slide 27 text

Error Code • Ϣʔβ͔Βͷ໰͍߹ΘͤΛޮ཰Խ͢Δཁ • ώΞϦϯάࣄ߲͔ΒݪҼಛఆ·ͰΛ௚݁ͤ͞Δ iOSDC Japan 2017

Slide 28

Slide 28 text

iOSDC Japan 2017

Slide 29

Slide 29 text

iOSDC Japan 2017

Slide 30

Slide 30 text

enum ApplicationError: Error { ... case hardwareNotReady var errorCode: Int { switch self { ... case hardwareNotReady: return -3000 } } var localizedDescription: String { ... case hardwareNotReady: return "Τϥʔίʔυ: \(errorCode)" } var localizedFailureReason: String { ... case hardwareNotReady: return "઀ଓʹࣦഊ͠·ͨ͠ɻBLEσόΠεͷిݯΛ֬͝ೝ͍ͩ͘͞ɻ" } } iOSDC Japan 2017

Slide 31

Slide 31 text

Error Codeͷར఺1 • ໰͍߹ΘͤͷແݴޠԽʹܨ͕Δ override func viewDidLoad() { ... service.connectToDevice { result in switch result { case .success(let data): ... case .failure(let error): Logger.shared.error(error) self.showAlert(withTitle: error.localizedDescription, message: error.localizedFailureReason) } } } iOSDC Japan 2017

Slide 32

Slide 32 text

Error Codeͷར఺2 • ϩάૹ৴͓͖ͯ͠ௐࠪΛޮ཰Խ • ໰͍߹ΘͤΛݩʹDashboardͰҰൃ ݕࡧ iOSDC Japan 2017

Slide 33

Slide 33 text

ϙΠϯτ • Τϥʔίʔυ͸ΞϓϦଆͰҰׅఆٛɾ؅ཧ͢Δͱྑͦ͞͏ • localizedFailureReasonͳͲ΋SDK͕ฦ͢΋ͷΛ࢖Θͳ͍ • 3rd party FWͰ͸nilΛฦͯ͠Δ͜ͱ͕ී௨ʹ͋Δ iOSDC Japan 2017

Slide 34

Slide 34 text

1. ΫϥογϡҎ֎ͷΤϥʔΛݕ஌Ͱ͖Δମ੍࡞Γ 2. ௐࠪʹඞཁͳώϯτ͸ͳΔ΂͘૿΍͢ 3. ໰͍߹Θͤ࣌ͷίετΛݮΒ͢ iOSDC Japan 2017

Slide 35

Slide 35 text

·ͱΊ • ෆ۩߹͕ൃੜ͢Δͱଟ͘ͷਓʹίετ͕͔͔Δ • ؆୯ͳ੔஍࡞ۀͰେ͖ͳϝϦοτ • ແବͳ΍ΓͱΓΛݮΒ͠շదͳτϥϒϧγϡʔςΟϯάΛ iOSDC Japan 2017