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

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

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for Yoichi Tagaya Yoichi Tagaya
September 16, 2017

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

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

Avatar for Yoichi Tagaya

Yoichi Tagaya

September 16, 2017
Tweet

More Decks by Yoichi Tagaya

Other Decks in Programming

Transcript

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

    ͷ࡞ऀ ‣ ଟ਺ͷϓϩμΫγϣϯ࠾༻ ‣ GitHubελʔ਺: ΋͏͙͢2000 • ϝϧΧϦͷiOSΤϯδχΞ ‣ ओʹΞϝϦΧ൛ΞϓϦΛ୲౰ ‣ 9/30 (౔) Mercari Tech Conf 2017ͰDIͷ࿩Λ͠·͢ J04%$Ͱ͸lίʔυੜ੒ʹΑΔ੩తͳ%FQFOEFODZ*OKFDUJPOzCZ!JTILBXBPO4FQ
  2. !ZPJDIJUHZ CrashlyticsͰҰ൪ॏཁͳ͜ͱ IUUQTEPDTGBCSJDJPBQQMFDSBTIMZUJDTUFTUDSBTIIUNMUSPVCMFTIPPUJOH func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions:

    [UIApplicationLaunchOptionsKey: Any]? ) -> Bool { Fabric.with([Crashlytics.self]) return true } ϩά͸ΫϥογϡޙʹΞϓϦ͕࠶ىಈͨ࣌͠ʹૹΒΕΔ application:didFinishLaunchingWithOptionsΛແࣄʹ௨ա͠ͳ͍ͱμϝ
  3. !ZPJDIJUHZ Ϣʔβ৘ใͷ௥Ճ γϯάϧτϯϝιου આ໌ TFU6TFS*EFOUJpFS @ 6TFS*EΛઃఆ͢Δ TFU6TFS&NBJM @ &NBJMΛઃఆ͢Δ

    6TFS*E͕͋Ε͹ී௨͸ෆཁ TFU6TFS/BNF @ Ϣʔβͷ໊લΛઃఆ͢Δ 6TFS*E͕͋Ε͹ී௨͸ෆཁ  ΧελϚʔαϙʔτͷ৘ใ͔Βௐ΂Δ࣌ʹศར  &NBJMͱϢʔβͷ໊લ͸໌Β͔ͳݸਓ৘ใͳͷͰ஫ҙ
  4. !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/จࣈྻʹ͢Δ͜ͱ΋ݕ౼
  5. !ZPJDIJUHZ ΧελϜϩάͷ௥Ճ ؔ਺ આ໌ $-4-PHW @GPSNBU BSHT Ϋϥογϡൃੜલͷϩά͕Ϋϥογϡʹඥ෇͚ΒΕΔ  ΫϥογϡͷݪҼʹͳΔ௚લͷಈ࡞͕Θ͔Δ

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

    Ϋϥογϡ͠ͳ͍͕ॏେͳΤϥʔΛ$SBTIMZUJDTͰ֬ೝͰ͖Δ  ϩάʹ࢒Δͷ͸ΞϓϦ࠶ىಈ·Ͱͷ࠷େݸͷΤϥʔ·Ͱ  $16ίετ͕͔͔ΔͷͰΦϒβʔόʔޮՌʹ஫ҙ  %8"3' %FCVH8JUI"UUSJCVUFE3FDPSE'PSNBU VOXJOEJOH
  7. !ZPJDIJUHZ OSLog/os_log var osLog = OSLog( subsystem: “com.my-company.LoggingSample", category: “ViewModel”

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

    JOGP ϝϞϦʔ  όοϑΝʔ͕͍ͬͺ͍ʹͳͬͨΒফ͑Δ  Τϥʔ͕ى͖ͨ৔߹͸อଘ͞ΕΔ EFGBVMU ετϨʔδ  ࠷ॳόοϑΝʔʹอଘ͞ΕΔ  ͍ͬͺ͍ʹͳͬͨΒετϨʔδʹҠ͞ΕΔ FSSPS ετϨʔδ  ϓϩηε಺ͷΤϥʔͰ࢖͏ GBVMU ετϨʔδ  ෳ਺ϓϩηε͕ؔΘΔΤϥʔͰ࢖͏
  9. !ZPJDIJUHZ ࣗ࡞ϩΨʔͷϩάϨϕϧ ϩάϨϕϧ ༻్ ॲཧ EFCVH %FCVH࣌ʹ͚ͩ ݟ͍ͨ৘ใ  $POTPMFʹͷΈग़ྗ

    JOGP "1*ίʔϧ౳ τϨʔε  $POTPMFͱ$-4-PHWͷग़ྗ FSSPS ϋϯυϦϯά ՄೳͳΤϥʔ  $POTPMFͱ$-4-PHWͷग़ྗ  $-4-PHWͷϝοηʔδ͸ݕࡧੑΛ্͛Δ GBUBM ૝ఆ֎ͷΤϥʔ  $POTPMFʹग़ྗ  SFDPSE&SSPSͰ$SBTIMZUJDTͷϨϙʔτΤϯτϦʔΛ࡞Δ  BTTFSUJPO'BJMVSF΋ೖΕͯ%FCVHϏϧυͰམͪΔΑ͏ʹ͢Δ
  10. !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])) } }
  11. !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) } }
  12. !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Ϋϥε
  13. !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 } ࠷ޙʹ ෆਖ਼ͳঢ়ଶΛҿΈࠐΜͰ͍ͨΒ࠷ѱͰ΋ϩάΛૹ͓ͬͯ͜͏ ݱࡏͷ࣮૷Ͱ͸͋Γ͑ͳͯ͘΋কདྷͷόάΛݕ஌͢ΔͨΊ
  14. !ZPJDIJUHZ %BUF 4QFBLFS 5JUMF  !UFOOUFOO (PʹΑΔJ04ΞϓϦͷ։ൃ  !DIVHBO[Z ϝϧΧϦͰ࣮ࢪͨ͠աڈ࠷େن໛ͷ"#ςετʮυϩϫʔWTԼλϒʯͷ෣୆ཪ

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