将ErrorType转换为NSError会丢失关联的对象

Ben*_* Lu 57 error-handling swift swift2

在Swift 2.0中NSError符合ErrorType协议.

对于自定义错误,我们可以为某些情况指定关联对象,如下所示.

enum LifeError: ErrorType {
    case BeBorn
    case LostJob(job: String)
    case GetCaughtByWife(wife: String)
    ...
}
Run Code Online (Sandbox Code Playgroud)

我们可以轻松地做到以下几点:

do {
    try haveAffairWith(otherPerson)
} catch LifeError.GetCaughtByWife(let wife) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我们希望它作为一个传递到其他地方NSError,它就会丢失它的关联对象信息.

println("\(LifeError.GetCaughtByWife("Name") as NSError)")
Run Code Online (Sandbox Code Playgroud)

打印:

Error Domain=... Code=1 "The operation couldn't be completed". (... error 1)
Run Code Online (Sandbox Code Playgroud)

userInfonil.

wife和哪里有联系ErrorType

Igo*_*ilo 43

Xcode 8中的新功能:CustomNSError 协议.

enum LifeError: CustomNSError {
    case beBorn
    case lostJob(job: String)
    case getCaughtByWife(wife: String)

    static var errorDomain: String {
        return "LifeError"
    }

    var errorCode: Int {
        switch self {
        case .beBorn:
            return 0
        case .lostJob(_):
            return 1
        case .getCaughtByWife(_):
            return 2
        }
    }

    var errorUserInfo: [String : AnyObject] {
        switch self {
        case .beBorn:
            return [:]
        case .lostJob(let job):
            return ["Job": job]
        case .getCaughtByWife(let wife):
            return ["Wife": wife]
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


ilu*_*pra 23

一个ErrorType不能真正被转换为NSError,你必须采取相关的数据,并将其打包成一个NSError自己.

do {
    try haveAffairWith(otherPerson)
} catch LifeError.GetCaughtByWife(let wife) {
    throw NSError(domain:LifeErrorDomain code:-1 userInfo:
        [NSLocalizedDescriptionKey:"You cheated on \(wife)")
}
Run Code Online (Sandbox Code Playgroud)

编辑:实际上你可以从中执行ErrorType转换NSError,但是NSError你从默认实现得到的是非常原始的.我在我的应用程序中正在做的是挂钩应用程序:willPresentError:在我的应用程序委托中并使用自定义类来读取我的应用程序ErrorType并装饰NSErrors以返回.


ork*_*den 14

NSError在每个catch块中创建一个可以导致大量复制和粘贴以将您的自定义转换ErrorTypeNSError.我把它抽象出类似@powertoold.

protocol CustomErrorConvertible {
    func userInfo() -> Dictionary<String,String>?
    func errorDomain() -> String
    func errorCode() -> Int
}
Run Code Online (Sandbox Code Playgroud)

这个扩展可以包含代码,这是LifeError我们已经拥有的代码以及我们可能创建的其他自定义错误类型.

extension CustomErrorConvertible {
    func error() -> NSError {
        return NSError(domain: self.errorDomain(), code: self.errorCode(), userInfo: self.userInfo())
    }
}
Run Code Online (Sandbox Code Playgroud)

关闭实施!

enum LifeError: ErrorType, CustomErrorConvertible {
    case BeBorn
    case LostJob(job: String)
    case GetCaughtByPolice(police: String)

    func errorDomain() -> String {
        return "LifeErrorDomain"
    }

    func userInfo() -> Dictionary<String,String>? {
        var userInfo:Dictionary<String,String>?
        if let errorString = errorDescription() {
            userInfo = [NSLocalizedDescriptionKey: errorString]
        }
        return userInfo
    }

    func errorDescription() -> String? {
        var errorString:String?
        switch self {
        case .LostJob(let job):
            errorString = "fired as " + job
        case .GetCaughtByPolice(let cops):
            errorString = "arrested by " + cops
        default:
            break;
        }
        return errorString
    }

    func errorCode() -> Int {
        switch self {
        case .BeBorn:
            return 1
        case .LostJob(_):
            return -9000
        case .GetCaughtByPolice(_):
            return 50
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是如何使用它.

func lifeErrorThrow() throws {
    throw LifeError.LostJob(job: "L33tHax0r")
}

do {
    try lifeErrorThrow()
}
catch LifeError.BeBorn {
  print("vala morgulis")
}
catch let myerr as LifeError {
    let error = myerr.error()
    print(error)
}
Run Code Online (Sandbox Code Playgroud)

您可以轻松地将某些功能,如func userInfo() -> Dictionary<String,String>?LifeErrorextension CustomErrorConvertible或不同的分机.

不像上面那样对错误代码进行硬编码,而是枚举可能更可取.

enum LifeError:Int {
  case Born
  case LostJob
}
Run Code Online (Sandbox Code Playgroud)


pow*_*old 6

我对这个问题的解决方案是创建一个符合Int,ErrorType的枚举:

enum AppError: Int, ErrorType {
    case UserNotLoggedIn
    case InternetUnavailable
}
Run Code Online (Sandbox Code Playgroud)

然后扩展枚举以符合CustomStringConvertible和一个名为CustomErrorConvertible的自定义协议:

extension AppError: CustomStringConvertible, CustomErrorConvertible

protocol CustomErrorConvertible {
    var error: NSError { get }
}
Run Code Online (Sandbox Code Playgroud)

对于描述和错误,我打开了AppError.例:

Description:    switch self {
            case .UserNotLoggedIn: return NSLocalizedString("ErrorUserNotLoggedIn", comment: "User not logged into cloud account.")
            case .InternetUnavailable: return NSLocalizedString("ErrorInternetUnavailable", comment: "Internet connection not available.")
            }

Error:    switch self {
            case .UserNotLoggedIn: errorCode = UserNotLoggedIn.rawValue; errorDescription = UserNotLoggedIn.description
            case .InternetUnavailable: errorCode = InternetUnavailable.rawValue; errorDescription = InternetUnavailable.description
            }
Run Code Online (Sandbox Code Playgroud)

然后我编写了自己的NSError:

return NSError(domain:NSBundle.mainBundle().bundleIdentifier!, code:errorCode, userInfo:[NSLocalizedDescriptionKey: errorDescription])
Run Code Online (Sandbox Code Playgroud)