如何在 swift 中处理 errors/exceptions

How to handle errors/exceptions in swift

这个标题听起来很笼统,尽管它是一个特定的问题。我只是不知道如何用更好的方式来描述它...... 我在 swift 中阅读了很多关于错误处理的内容。但我仍然想不出如何解决这个简单的(至少在 objective-C)任务。 我有一个文本字段,想读出 string-value...然后将其格式化为 Date 值。到目前为止没问题。但是,如果您输入的值与指定的日期格式不匹配,我会返回一个错误(这没关系……它的格式不正确)。在这种情况下,我只想保存一个标准值。在 Objective-C 中,我会使用 @try-@catch 循环来完成此操作。 swift 中不再存在那种异常处理,对吗? 这是我的 (Swift 2) 代码。希望有人有答案。

func getDateFromTextfield() throws -> NSDate
{
    let formatter:NSDateFormatter = NSDateFormatter()
    formatter.dateFormat = "dd.MM.yyyy"
    formatter.timeZone = NSTimeZone(name: "UTC")

// Here should be a "throw expression" but I dont know how to set it. 

    let date = formatter.dateFromString(dictOfLabelsAndText["Birthdate"] as! String)!

    return date
}

do
{
    child.birthdateAT = try self.getDateFromTextfield()
}
catch {
    child.birthdateAT = formatter.dateFromString("01.01.2000")
    print("wrong date") //Or whatever error
}

选择您的错误 - 例如

enum DateError: ErrorType {
    case BadDate
    case Whatever
}

然后把它扔到你评论的地方

throw DateError.BadDate

Swift do-try-catch 语法旨在处理类似于 Objective-C 中的 NSError 模式的错误,不是为了处理致命的 errors/exceptions。不要被 Swift 的错误处理 do-try-catch 与 [=23 的完全不同的 Objective-C 异常处理模式的相似性混淆=]-@catch.

只有在确信它们不可能失败时,才应使用强制解包 (!) 和强制类型转换 (as!)。如果它们可能会失败(如本例),您应该优雅地检测到这种情况并相应地处理它。

例如,您可以使用 Swift 错误处理来传达将字符串转换为日期的失败(然后使用 do-try-catch当您调用它以检测和处理该错误时的模式):

enum DateError: Error {
    case badDate
    case dateNotFound
}

func getDateFromTextfield() throws -> Date {
    let formatter = DateFormatter()
    formatter.dateFormat = "dd.MM.yyyy"
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    
    guard let dateString = dictOfLabelsAndText["Birthdate"] as? String else {
        throw DateError.dateNotFound
    }
    
    guard let date = formatter.date(from: dateString) else {
        throw DateError.badDate
    }
    
    return date
}

那么你可以这样做:

do {
    child.birthdateAT = try getDateFromTextfield()
} catch {
    child.birthdateAT = formatter.date(from: "01.01.2000")
}

或者,更简洁地说,使用 try?nil 合并运算符:

child.birthdateAT = try? getDateFromTextfield() ?? formatter.date(from: "01.01.2000")

或者,您可以将方法更改为 return 可选方法并使用 nil 作为检测故障的方法:


func getDateFromTextfield() -> Date? {
    let formatter = DateFormatter()
    formatter.dateFormat = "dd.MM.yyyy"
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    
    guard let dateString = dictOfLabelsAndText["Birthdate"] as? String else {
        return nil
    }
    
    return formatter.date(from: dateString)
}

然后做:

if let birthDate = getDateFromTextfield() {
    child.birthdateAT = birthDate
} else {
    child.birthdateAT = formatter.date(from: "01.01.2000")
}

或者,再次使用 nil 合并运算符:

child.birthdateAT = getDateFromTextfield() ?? formatter.date(from: "01.01.2000")

但是,最重要的是,不要使用 ! 来解包一个可选的,除非你知道它永远不会是 nil。否则,使用可选绑定 and/or guard 语句来优雅地检测并报告故障。


这已针对现代版本 Swift 进行了更新。原始 Swift 2 个答案,请参阅此答案的 previous revision

Swift 3
我试过了。可以用但不确定方法是否正确

 enum DateError: Error, CustomStringConvertible {

    case badDate

    var description: String {
        switch self {

        case .badDate:
            return "Error: Invalid date detected."
        }
    }


}


func convertAMtoDateTime(amTime: String) throws -> String{


    let fromFormat: String = "hh:mm a"

    let toFormat: String = "yyyy-MM-dd hh:mm:ss"

    let formatter = DateFormatter()

    formatter.dateFormat = fromFormat

    let amDate = formatter.date(from: amTime)

    let dateTimeFormatter    = DateFormatter()

    dateTimeFormatter.dateFormat = toFormat

    var dateTime: String = ""

    if(amDate != nil){

         dateTime = dateTimeFormatter.string(from: amDate!)

    }
    else{

        throw DateError.badDate

    }

    return dateTime


}