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

モバイルアプリで困らないエラーハンドリングとロギングのベストプラクティス

 モバイルアプリで困らないエラーハンドリングとロギングのベストプラクティス

iOSDC 2017 in Tokyo, September 16-17, 2017
https://iosdc.jp/2017/node/1482

4fec50a13364f1766354ae9a9ce5480d?s=128

Yoichi Tagaya

September 16, 2017
Tweet

Transcript

  1. !ZPJDIJUHZ ϞόΠϧΞϓϦͰࠔΒͳ͍ ΤϥʔϋϯυϦϯάͱ ϩΪϯάͷϕετϓϥΫςΟε ଟլ୩ ༸Ұ iOSDC JAPAN 2017

  2. !ZPJDIJUHZ ࣗݾ঺հ ʙ ଟլ୩ ༸Ұ • Swinject (Dependency Injection Framework)

    ͷ࡞ऀ ‣ ଟ਺ͷϓϩμΫγϣϯ࠾༻ ‣ GitHubελʔ਺: ΋͏͙͢2000 • ϝϧΧϦͷiOSΤϯδχΞ ‣ ओʹΞϝϦΧ൛ΞϓϦΛ୲౰ ‣ 9/30 (౔) Mercari Tech Conf 2017ͰDIͷ࿩Λ͠·͢ J04%$Ͱ͸lίʔυੜ੒ʹΑΔ੩తͳ%FQFOEFODZ*OKFDUJPOzCZ!JTILBXBPO4FQ
  3. !ZPJDIJUHZ •ɹΤϯδχΞͷεΩϧ •ɹίʔυϨϏϡʔ •ɹϢχοτςετ •ɹ6*ࣗಈςετ •ɹखಈςετ •ɹΤϥʔϩά ࠓ೔ͷ࿩ ΞϓϦͷ඼࣭޲্ʹඞཁͳ͜ͱ

  4. !ZPJDIJUHZ ͜Μͳͷݟͨ͜ͱ͋Γ·ͤΜ͔ʁ ΫϥογϡͰ1ˑϨϏϡʔͷཛྷ ࠶ݱ͠ͳ͍ Ͳ͏͢Ε͹͍͍͔෼͔Βͳ͍ ΞϓϦΛόʔδϣϯΞοϓͨ͠

  5. !ZPJDIJUHZ Ϋϥογϡϩάͱ͍͑͹

  6. !ZPJDIJUHZ Crashlytics IUUQTXXXGBCSJDJP $SBTIMZUJDTΛਂ͘୳ͬͯΈΑ͏

  7. !ZPJDIJUHZ CrashlyticsͰҰ൪ॏཁͳ͜ͱ IUUQTEPDTGBCSJDJPBQQMFDSBTIMZUJDTUFTUDSBTIIUNMUSPVCMFTIPPUJOH func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions:

    [UIApplicationLaunchOptionsKey: Any]? ) -> Bool { Fabric.with([Crashlytics.self]) return true } ϩά͸ΫϥογϡޙʹΞϓϦ͕࠶ىಈͨ࣌͠ʹૹΒΕΔ application:didFinishLaunchingWithOptionsΛແࣄʹ௨ա͠ͳ͍ͱμϝ
  8. !ZPJDIJUHZ ىಈ࣌ application:didFinishLaunchingWithOptionsͰͦ͠͏ͳ͜ͱ • ֤छϑϨʔϜϫʔΫͷॳظԽ •ɹ%BUBCBTFͷϚΠάϨʔγϣϯ •ɹΩϟογϡͷΫϦΞ ϝΠϯεϨουΛ௕࣌ؒࢭΊͳ͍

  9. !ZPJDIJUHZ ಛʹґଘϥΠϒϥϦʹ஫ҙ IUUQTHJUIVCDPNQJOUFSFTU1*/3FNPUF*NBHFJTTVFT 1*/3FNPUF*NBHFࣗମ͸͍͍ϥΠϒϥϦͰ͢

  10. !ZPJDIJUHZ ͦΕͰ

  11. !ZPJDIJUHZ Crashlyticsͬͯ Πϯετʔϧ͢ΔҎ֎ʹ Կ͔ඞཁͳͷʁ

  12. !ZPJDIJUHZ Crashlyticsʹ͸ ศརͳ෇Ճ৘ใ͕͋Δ

  13. !ZPJDIJUHZ Ϣʔβ৘ใͷ௥Ճ γϯάϧτϯϝιου આ໌ TFU6TFS*EFOUJpFS @ 6TFS*EΛઃఆ͢Δ TFU6TFS&NBJM @ &NBJMΛઃఆ͢Δ

    6TFS*E͕͋Ε͹ී௨͸ෆཁ TFU6TFS/BNF @ Ϣʔβͷ໊લΛઃఆ͢Δ 6TFS*E͕͋Ε͹ී௨͸ෆཁ  ΧελϚʔαϙʔτͷ৘ใ͔Βௐ΂Δ࣌ʹศར  &NBJMͱϢʔβͷ໊લ͸໌Β͔ͳݸਓ৘ใͳͷͰ஫ҙ
  14. !ZPJDIJUHZ Key/Valueͷ௥Ճ γϯάϧτϯϝιου આ໌ TFU0CKFDU7BMVF @GPS,FZ 4USJOHͳͲΛ,FZʹରͯ͠ઃఆ͢Δ TFU#PPM7BMVF @GPS,FZ #PPM஋Λ,FZʹରͯ͠ઃఆ͢Δ

    TFU*OU7BMVF @GPS,FZ *OU஋Λ,FZʹରͯ͠ઃఆ͢Δ TFU'MPBU7BMVF @GPS,FZ 'MPBU஋Λ,FZʹରͯ͠ઃఆ͢Δ  3FNPUF$POpH "#5FTU %PXOMPBEͨ͠Ϧιʔε+4ͷ7FSTJPO౳ʹ  ࠷େݸͷ,FZ·Ͱͭͷ,FZ7BMVF͕,#·Ͱ  ,FZ͕ͨ͘͞ΜඞཁͳΒ+40/จࣈྻʹ͢Δ͜ͱ΋ݕ౼
  15. !ZPJDIJUHZ ΧελϜϩάͷ௥Ճ ؔ਺ આ໌ $-4-PHW @GPSNBU BSHT Ϋϥογϡൃੜલͷϩά͕Ϋϥογϡʹඥ෇͚ΒΕΔ  ΫϥογϡͷݪҼʹͳΔ௚લͷಈ࡞͕Θ͔Δ

     ϩά͸࠷େ,# ߦจࣈ͘Β͍ͳΒߦ͘Β͍   ͋;ΕͨΒݹ͍΋ͷ͔Βফ͞ΕΔ  Ϣʔβߦಈ Πϕϯτ ͷϩά͸"OTXFST΍'JSFCBTFͳͲΛ࢖͏
  16. !ZPJDIJUHZ ඇΫϥογϡͷϨϙʔτΛ௥Ճ γϯάϧτϯϝιου આ໌ SFDPSE&SSPS @ ॏେͳΤϥʔͰϩάΤϯτϦʔΛ࡞Δ Ϩϙʔτ͸/PO'BUBMTάϧʔϓʹ·ͱΊΒΕΔ ΞϓϦ࠶ىಈ࣌ʹ$SBTIMZUJDTʹૹ৴͞ΕΔ 

    Ϋϥογϡ͠ͳ͍͕ॏେͳΤϥʔΛ$SBTIMZUJDTͰ֬ೝͰ͖Δ  ϩάʹ࢒Δͷ͸ΞϓϦ࠶ىಈ·Ͱͷ࠷େݸͷΤϥʔ·Ͱ  $16ίετ͕͔͔ΔͷͰΦϒβʔόʔޮՌʹ஫ҙ  %8"3' %FCVH8JUI"UUSJCVUFE3FDPSE'PSNBU VOXJOEJOH
  17. !ZPJDIJUHZ CrashlyticsΛ OSLogͱ૊Έ߹Θͤͯ ࣗ࡞ͷϩΨʔΛ࡞Γ·͢

  18. !ZPJDIJUHZ OSLog/os_log var osLog = OSLog( subsystem: “com.my-company.LoggingSample", category: “ViewModel”

    ) os_log(“Hello world!”, log: osLog, type: .default) ࢖͍ํ J04͔Β࢖͑ΔΑ͏ʹͳͬͨϩάͷ࢓૊Έ
  19. !ZPJDIJUHZ OSLogType IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOPTMPHHJOH ϩάϨϕϧ อଘઌ ಛ௃ EFCVH ͳ͠  σόοά༻

    JOGP ϝϞϦʔ  όοϑΝʔ͕͍ͬͺ͍ʹͳͬͨΒফ͑Δ  Τϥʔ͕ى͖ͨ৔߹͸อଘ͞ΕΔ EFGBVMU ετϨʔδ  ࠷ॳόοϑΝʔʹอଘ͞ΕΔ  ͍ͬͺ͍ʹͳͬͨΒετϨʔδʹҠ͞ΕΔ FSSPS ετϨʔδ  ϓϩηε಺ͷΤϥʔͰ࢖͏ GBVMU ετϨʔδ  ෳ਺ϓϩηε͕ؔΘΔΤϥʔͰ࢖͏
  20. !ZPJDIJUHZ Console App IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZXXED IUUQTNFEJVNDPN!BCKVSBUPVOJpFEMPHHJOHBOEBDUJWJUZUSBDJOHBB⒎FGC • "DUJWJUZ5SBDJOHͱ૊Έ߹ ΘͤΔͱศར • ෳ਺ϓϩηε͕ؔΘΔΞ

    ϓϦͷσόοάͰศར w .BD"QQ w 8BUDI"QQ • ݱঢ়͸4XJGU͔Β͸௚઀࢖ ͑ͳ͍ w ࢖͏ʹ͸ԼͷϦϯΫࢀর
  21. !ZPJDIJUHZ ͔͠͠ͳ͕Β ࠓճ͸γϯϓϧͳ࢖༻๏ʹཹΊ·͢ # $SBTIMZUJDT͚ͩͰे෼ڧྗ

  22. !ZPJDIJUHZ ࣗ࡞ϩΨʔͷϩάϨϕϧ ϩάϨϕϧ ༻్ ॲཧ EFCVH %FCVH࣌ʹ͚ͩ ݟ͍ͨ৘ใ  $POTPMFʹͷΈग़ྗ

    JOGP "1*ίʔϧ౳ τϨʔε  $POTPMFͱ$-4-PHWͷग़ྗ FSSPS ϋϯυϦϯά ՄೳͳΤϥʔ  $POTPMFͱ$-4-PHWͷग़ྗ  $-4-PHWͷϝοηʔδ͸ݕࡧੑΛ্͛Δ GBUBM ૝ఆ֎ͷΤϥʔ  $POTPMFʹग़ྗ  SFDPSE&SSPSͰ$SBTIMZUJDTͷϨϙʔτΤϯτϦʔΛ࡞Δ  BTTFSUJPO'BJMVSF΋ೖΕͯ%FCVHϏϧυͰམͪΔΑ͏ʹ͢Δ
  23. !ZPJDIJUHZ LogΫϥε final class Log { static func debug(message: String)

    { os_log("⚒%@", type: .debug, message) } static func info(message: String) { os_log("ℹ%@", type: .debug, message) CLSLogv("%@", getVaList([message])) } static func error(message: String) { os_log("❗%@", type: .debug, message) CLSLogv("[Error] %@", getVaList([message])) } }
  24. !ZPJDIJUHZ LogΫϥε final class Log { static func fatal( message:

    String, file: String = #file, function: String = #function, line: Int = #line) { os_log("%@", log: .default, type: .debug, message) let fileName = file.components(separatedBy: "/").last ?? "" let error = NSError( domain: "\(fileName):\(function)", code: line, userInfo: ["message": message] ) Crashlytics.sharedInstance().recordError(error) assertionFailure(message) } }
  25. !ZPJDIJUHZ final class Log { static func error(error: Error) {

    let message = String(reflecting: error) os_log("❗%@", log: .default, type: .debug, message) CLSLogv("[Error] %@", getVaList([message])) } static func fatal(error: Error) { let message = String(reflecting: error) os_log("%@", log: .default, type: .debug, message) Crashlytics.sharedInstance() .recordError(error as NSError) assertionFailure(message) } } LogΫϥε
  26. !ZPJDIJUHZ Demo  -PHTXJGUIUUQTHJTUHJUIVCDPNZPJDIJUHZBEBBEFGFBBCB  "QQ%FMFHBUFTXJGUIUUQTHJTUHJUIVCDPNZPJDIJUHZFEBGBCGFCFBCDF  7JFX$POUSPMMFSTXJGUIUUQTHJTUHJUIVCDPNZPJDIJUHZFCBFGEECBBD

  27. !ZPJDIJUHZ Demoͨ͜͠ͱ

  28. !ZPJDIJUHZ Demoͨ͜͠ͱ

  29. !ZPJDIJUHZ guard let something = something else { // Swallow

    return } guard !array.isEmpty else { // Swallow return } guard let something = something else { Log.fatal(message: "something is nil unexpectedly.") return } guard !array.isEmpty else { Log.fatal(message: "array is empty.") return } ࠷ޙʹ ෆਖ਼ͳঢ়ଶΛҿΈࠐΜͰ͍ͨΒ࠷ѱͰ΋ϩάΛૹ͓ͬͯ͜͏ ݱࡏͷ࣮૷Ͱ͸͋Γ͑ͳͯ͘΋কདྷͷόάΛݕ஌͢ΔͨΊ
  30. !ZPJDIJUHZ %BUF 4QFBLFS 5JUMF  !UFOOUFOO (PʹΑΔJ04ΞϓϦͷ։ൃ  !DIVHBO[Z ϝϧΧϦͰ࣮ࢪͨ͠աڈ࠷େن໛ͷ"#ςετʮυϩϫʔWTԼλϒʯͷ෣୆ཪ

     !LJUBTVLF *OUSPEVDJOHQSPUPCVGJO4XJGU  !KBSJOPTVLF 64൛.FSDBSJΛ·Δ͝ͱ͔Β࡞Γ௚ͨ͠࿩  !NPUPLJFF ݁ࠗࣜΛࢧٕ͑ͨज़'JSFCBTFΛ׆༻ͨ͠αʔόϨεJ04ΞϓϦέʔγϣϯ։ൃ  !EUWE ϝϧΧϦΞοςΛࢧ͑ΔΦʔτϚτϯ  !KPMMZKPFTUFS པΉ͔Βϓογϡ௨஌ͷ࢖͍ํΛ͓Ζ͔ͦʹ͠ͳ͍Ͱ͘Εʂ ʙϓογϡ௨஌ͷදݱɺྺ࢙ɺ࠷৽ಈ޲·Ͱʙ Thank you .PSFGSPN BUJ04%$