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

Swift 2 Error Handling in Practice

cockscomb
August 30, 2015

Swift 2 Error Handling in Practice

Presented @ Swift 2 Symposium #2

cockscomb

August 30, 2015
Tweet

More Decks by cockscomb

Other Decks in Programming

Transcript

  1. Swift 2

    Error Handling in Practice

    View Slide

  2. cockscomb

    View Slide

  3. View Slide

  4. Recent work
    • Rewrite Hatena Blog for iOS with Swift
    • Hatena Summer Internship 2015 “iOS App Course”
    • Sample code: hatena/swift-Sample-GitHubSearch
    • Textbook: Available soon
    • Secret projects‥

    View Slide

  5. I moved our codes 

    into Swift 2 the past week

    View Slide

  6. Swift 2

    Error Handling in Practice

    View Slide

  7. Which is better?
    func parseInt(string: String) -> Int?
    func parseInt(string: String) throws -> Int
    func parseInt(string: String) throws -> Int?

    View Slide

  8. Which is better?
    func parseInt(string: String) -> Int?

    View Slide

  9. Which is better?
    func parseJSON(data: NSData) -> JSONObject?
    func parseJSON(data: NSData) throws -> JSONObject
    func parseJSON(data: NSData) throws -> JSONObject?

    View Slide

  10. Which is better?
    func parseJSON(data: NSData) throws -> JSONObject

    View Slide

  11. func parseJSON(data: NSData) throws -> JSONObject
    do {
    let json = try parseJSON(data)
    // Something
    } catch {
    // Handle error
    }
    if let json = try? parseJSON(data) {
    // Something
    }

    View Slide

  12. enum JSONDecodeError: ErrorType {
    case MissingRequiredKey(String)
    case UnexpectedType(key: String,
    expected: Any.Type, actual: Any.Type)
    }
    struct JSONObject {
    let raw: [String : AnyObject]
    func getValue(key: String) throws -> T {
    guard let value = raw[key] else {
    throw JSONDecodeError.MissingRequiredKey(key)
    }
    guard let typedValue = value as? T else {
    throw JSONDecodeError.UnexpectedType(
    key: key,
    expected: T.self,
    actual: value.dynamicType)
    }
    return typedValue
    }
    }

    View Slide

  13. do {
    let json = try parseJSON(data)
    let userName: String = try json.getValue("user_name")
    // Something
    } catch {
    // Handle error
    }
    if let json = try? parseJSON(data),
    let userName: String = try? json.getValue("user_name") {
    // Something
    }

    View Slide

  14. Which is better?
    enum JSONDecodeError: ErrorType {
    case MissingRequiredKey(String)
    case UnexpectedType(key: String,
    expected: Any.Type,
    actual: Any.Type)
    }
    enum JSONDecodeError: ErrorType {
    case MissingRequiredKey
    case UnexpectedType
    }

    View Slide

  15. Which is better?
    enum JSONDecodeError: ErrorType {
    case MissingRequiredKey(String)
    case UnexpectedType(key: String,
    expected: Any.Type,
    actual: Any.Type)
    }

    View Slide

  16. Do more better
    enum JSONDecodeError: ErrorType,
    CustomDebugStringConvertible {
    case MissingRequiredKey(String)
    case UnexpectedType(key: String,
    expected: Any.Type, actual: Any.Type)
    var debugDescription: String {
    switch self {
    case .MissingRequiredKey(let key):
    return "Required key '\(key)' missing"
    case let .UnexpectedType(key: key,
    expected: expected, actual: actual):
    return "Unexpected type '\(actual)' was
    supplied for '\(key): \(expected)'"
    }
    }
    }

    View Slide

  17. Do more better
    struct JSONObject {
    let raw: [NSString : AnyObject]
    /**
    Get typed value for the key
    - parameters:
    - key: JSON key
    - returns: Typed value
    */
    func getValue(key: String) throws -> T {
    guard let value = raw[key] else {
    throw JSONDecodeError.MissingRequiredKey(key)
    }
    ...

    View Slide

  18. Do more better
    struct JSONObject {
    let raw: [NSString : AnyObject]
    /**
    Get typed value for the key
    - parameters:
    - key: JSON key
    - returns: Typed value
    - throws: JSONDecodeError
    */
    func getValue(key: String) throws -> T {
    guard let value = raw[key] else {
    throw JSONDecodeError.MissingRequiredKey(key)
    }
    ...

    View Slide

  19. as NSError
    enum MyError: ErrorType {
    case SuperError
    }
    let error = MyError.SuperError as NSError
    print(error.localizedDescription)
    // The operation couldn’t be completed.

    (Module.MyError error 0.)

    View Slide

  20. enum MyError: ErrorType {
    case SuperError
    static func description(code: Int) -> String? {
    switch code {
    case 0: return "Super error occurred"
    default: return nil
    }
    }
    }
    NSError.setUserInfoValueProviderForDomain("Module.MyError")
    { (error, userInfoKey) -> AnyObject? in
    switch userInfoKey {
    case NSLocalizedDescriptionKey:
    return MyError.description(error.code)
    default: break
    }
    return nil
    }
    let error = MyError.SuperError as NSError
    print(error.localizedDescription) // Super error occurred

    View Slide

  21. Error handling in practice
    • Functions can return Optional type or throw error
    • ErrorType should provide informations in detail
    • Documentation comment with possible error kind
    • Treating ErrorType as NSError have some problems

    View Slide