$30 off During Our Annual Pro Sale. View Details »

if (error) { // TODO }

if (error) { // TODO }

In diesem Vortrag soll der Status Quo von Fehlerbehandlungen unter iOS analysiert werden und ein Vorschlag gemacht werden, wie die Responder Chain genutzt werden kann, um den Fluss von Fehlern durch die App zu steuern. Durch eine zentralisierte Fehlerbehandlung sollte nach diesem Talk kein if (error) { // TODO. } im Code mehr nötig sein.

Sven Titgemeyer

September 15, 2018
Tweet

More Decks by Sven Titgemeyer

Other Decks in Programming

Transcript

  1. if (error) {
    // TODO
    }
    Sven Titgemeyer 15.09.2018

    View Slide

  2. Wer bin ich?
    • iOS Enthusiast
    • Freelancer
    • große Projekte
    • Student
    • kleine Projekte
    • Open Source (iCarambaa)
    @s_titgemeyer

    View Slide

  3. - (void)someMethod {
    NSURLSession *session = [NSURLSession sharedSession];
    [session dataTaskWithURL:url completionHandler:^(NSData *data,
    NSURLResponse *response, NSError *error) {
    if (error) {
    // TODO
    return;
    }
    // Continue with success case.
    }];
    }

    View Slide

  4. func someFunction() {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
    guard let data = data else {
    // TODO
    return
    }
    // Continue...
    }
    }

    View Slide

  5. func someFunction() {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
    guard let data = data else {
    print("Error: \(error!)")
    return
    }
    // Continue...
    }
    }

    View Slide

  6. View Slide

  7. Agenda
    • Error Handling Patterns
    • Was macht der Mac?
    • Error erstellen
    • Error weiterreichen
    • Error anzeigen Metal
    Systemframeworks
    Andere Frameworks
    Eigene Frameworks
    App
    Error
    Error

    View Slide

  8. UIAlertView

    View Slide

  9. UIAlertView
    ^(NSData *data, NSURLResponse *response, NSError *error) {
    if (data) {
    // Success case...
    } else {
    dispatch_async(dispatch_get_main_queue(), ^{
    UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:@"Error" message:error.localizedDescription delegate:nil
    cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [alert show];
    });
    }
    }

    View Slide

  10. UIAlertView

    View Slide

  11. UIAlertController

    View Slide

  12. UIAlertController
    -[UIAlertController show]

    View Slide

  13. UIAlertController
    •Ein Alert ist ein View Controller
    •Wollen wir einen View Controller an x verschiedenen Stellen
    initialisieren?
    •… oder innerhalb eines Models?
    •Fragen wir Stackoverflow!
    •“Present UIAlertController without View Controller”

    View Slide

  14. UIAlertController

    View Slide

  15. UIAlertController
    • Eigene Alert über oder unter Systemalerts?
    • Window teilen oder kriegt jedes ein eigenes?
    • Mehrere Alerts übereinander?
    Kurz:
    Don’t

    View Slide

  16. macOS

    View Slide

  17. macOS
    @interface NSResponder(NSErrorPresentation)
    - (BOOL)presentError:(NSError *)error;
    - (NSError *)willPresentError:(NSError *)error;
    @end

    View Slide

  18. macOS
    dispatch_async(dispatch_get_main_queue(), ^{
    BOOL didRecover = [self presentError:error];
    if (didRecover) {
    // Retry.
    }
    }

    View Slide

  19. macOS

    View Slide

  20. NSError
    Code
    Domain
    NSLocalizedDescriptionKey
    NSLocalizedFailureErrorKey
    NSLocalizedFailureReasonErrorKey
    NSLocalizedRecoverySuggestionErrorKey

    Beispiel:
    NSFileWriteOutOfSpaceError
    “The image library could not be
    saved.”
    “The volume Macintosh HD is
    out of space.”
    NSLocalizedRecoveryOptionsErrorKey
    NSRecoveryAttempterErrorKey

    View Slide

  21. Localized Description
    • Beschreibung aus dem Inhalt des Errors
    • “The image library could not be saved. The volume Macintosh HD is
    out of space.”
    • Mehrere Regeln, je nachdem, welche Informationen gesetzt sind.
    • Dokumentation nur in den Foundation Release Notes: 

    https://developer.apple.com/library/archive/releasenotes/Foundation/RN-Foundation/index.html

    View Slide

  22. Responder Chain
    UIResponder
    UIView UIApplication
    UIViewController

    View Slide

  23. UIView
    UIApplication
    UIViewController
    Superview
    UIViewController

    View Slide

  24. UIResponder erweitern
    @interface UIResponder (STIErrorPresentation)
    - (void)presentError:(NSError *)error completionHandler:(nullable void
    (^)(BOOL didRecover))completionHandler;
    - (nullable NSError *)willPresentError:(NSError *)error;
    @end

    View Slide

  25. UIApplication
    UIViewController
    UIViewController AppDelegate
    willPresentError: willPresentError: willPresentError: willPresentError:
    presentError: presentError:
    presentError: presentError:
    Achtung: Niemals [UIResponder presentError:] überschreiben

    View Slide

  26. View Slide

  27. Erneut versuchen

    View Slide

  28. NSError
    Code
    Domain
    NSLocalizedDescriptionKey
    NSLocalizedFailureErrorKey
    NSLocalizedFailureReasonErrorKey
    NSLocalizedRecoverySuggestionErrorKey

    Beispiel:
    NSFileWriteOutOfSpaceError
    “The image library could not be
    saved.”
    “The volume Macintosh HD is
    out of space.”
    NSLocalizedRecoveryOptionsErrorKey
    NSRecoveryAttempterErrorKey

    View Slide

  29. @interface NSObject(NSErrorRecoveryAttempting)
    - (BOOL)attemptRecoveryFromError:(NSError *)error
    optionIndex:(NSUInteger)recoveryOptionIndex;
    @end

    View Slide

  30. STIRecoveryAttempter *a = [STIRecoveryAttempter new];
    [a addOkayRecoveryOption];
    [a addRecoveryOptionWithTitle: @"Retry" recoveryAttempt:^BOOL{
    return YES;
    }];
    NSError *_error = [error addingObject:a
    forUserInfoKey:NSRecoveryAttempterErrorKey];
    [self presentError:_error completionHandler:^(BOOL didRecover) {
    if (didRecover) {
    [self loadFlightStatusUsingFlightnumber];
    }
    }];

    View Slide

  31. Problem
    • Error Fall wird komplizierter
    • Duplizierter Code
    • Retry Option wird an jeden Error angehangen
    • Besser: Konfiguriere Errors an zentraler Stelle!

    View Slide

  32. UIApplication
    UIViewController
    UIViewController AppDelegate
    willPresentError: willPresentError: willPresentError: willPresentError:
    presentError: presentError:
    presentError: presentError:

    View Slide

  33. UIApplication
    UIViewController
    UIViewController AppDelegate
    willPresentError: willPresentError: willPresentError: willPresentError:

    View Slide

  34. UIApplication
    UIViewController
    UIViewController
    willPresentError: willPresentError: willPresentError:
    STIErrorConfigurator
    willPresentError:
    STIErrorConfigurator
    STIErrorConfigurator
    NSError
    -domain
    -code

    View Slide

  35. UIApplication
    UIViewController
    UIViewController
    willPresentError: willPresentError: willPresentError:
    STIErrorConfigurator
    willPresentError:
    STIErrorConfigurator
    STIErrorConfigurator
    NSError
    -domain
    -code
    Recovery
    Attempter

    View Slide

  36. UIApplication
    UIViewController
    UIViewController
    willPresentError: willPresentError: willPresentError:
    STIErrorConfigurator
    willPresentError:
    STIErrorConfigurator
    STIErrorConfigurator
    NSError
    -domain
    -code
    Recovery
    Attempter

    View Slide

  37. UIApplication
    UIViewController
    UIViewController
    willPresentError: willPresentError: willPresentError:
    STIErrorConfigurator
    willPresentError:
    STIErrorConfigurator
    STIErrorConfigurator
    NSError
    -domain
    -code
    Recovery
    Attempter

    View Slide

  38. Abfangen

    View Slide

  39. @interface UIResponder (STIErrorPresentation)
    - (BOOL)canInterceptError:(NSError *)error;
    - (void)interceptError:(NSError *)error
    completionHandler:(void (^)(BOOL didRecover))completionHandler;
    @end
    Error Domains nutzen

    View Slide

  40. STIErrorHandling
    • Open Source
    • Fork von HRSCustomErrorHandling
    • Schlank
    • Optimal auch für kleine Projekte
    • https://github.com/iCarambaa/STIErrorHandling

    View Slide

  41. Demo

    View Slide

  42. Zusammenfassung
    • Jeder Error der auftreten kann, tritt auch auf
    • Informationen aus NSError nutzen
    • Responder Chain kann den Fluss übernehmen
    • Besonders in kleinen Projekten eine einfache Lösung

    View Slide

  43. Q&A
    • Error erstellen
    • Responder Chain
    • Error-Präsentation
    • Error Configurator
    @s_titgemeyer
    • STIErrorHandling
    • Swift

    View Slide