错误处理斯威夫特语言错误处理斯威夫特语言(Error-Handling in Swift-Langu

2019-05-09 05:20发布

我没有过多解读斯威夫特但有一两件事我注意到的是,没有异常。 那么他们是怎么做到的错误迅速处理? 有没有人找到任何有关错误处理?

Answer 1:

迅速2&3

事情已经在斯威夫特2改了一下,因为有一个新的错误处理机制,这是较为相似的异常,但不同的细节。

1.指示错误的可能性

如果函数/方法要表明它可能会抛出一个错误,它应该包含throws关键字这样

func summonDefaultDragon() throws -> Dragon

注意:有错误的类型的函数实际上可以抛出不规范。 这个声明只是说,该函数可以抛出任何类型的执行错误类型的实例,或者是不扔的。

2.可能会引发错误调用函数

为了调用函数,你需要使用try关键字,这样

try summonDefaultDragon()

此线通常应该是这样的本DO-catch块

do {
    let dragon = try summonDefaultDragon() 
} catch DragonError.dragonIsMissing {
    // Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
    // Other specific-case error-handlng
} catch {
    // Catch all error-handling
}

注:catch子句使用相匹配的,所以你是非常灵活这里斯威夫特模式的所有强大功能。

您可能决定传播的错误,如果你的呼吁从本身标有功能的投掷函数throws关键字:

func fulfill(quest: Quest) throws {
    let dragon = try summonDefaultDragon()
    quest.ride(dragon)
} 

或者,您可以使用调用函数投掷try?

let dragonOrNil = try? summonDefaultDragon()

这样,你要么返回值或为零,如果发生错误。 使用这种方式,你没有得到错误的对象。

这意味着你还可以结合try? 有用之类的语句:

if let dragon = try? summonDefaultDragon()

要么

guard let dragon = try? summonDefaultDragon() else { ... }

最后,你可以决定你知道错误不会实际发生(例如,因为你已经检查是先决条件),并使用try! 关键词:

let dragon = try! summonDefaultDragon()

如果函数实际上抛出一个错误,那么你会在你的应用程序获得了运行时错误,应用程序将终止。

3.抛出一个错误

为了抛出一个错误,你使用这样throw关键字

throw DragonError.dragonIsMissing

你可以抛出任何符合ErrorType协议。 对于初学者NSError符合本协议,但你可能会喜欢去与基于枚举的ErrorType ,使您将多个相关的错误,可能有额外的数据块,这样

enum DragonError: ErrorType {
    case dragonIsMissing
    case notEnoughMana(requiredMana: Int)
    ...
}

之间新夫特2&3错误机构和Java / C#主要区别/ C ++式例外如下:

  • 语法是有点不同: do-catch + try + defer VS传统try-catch-finally语法。
  • 异常处理通常会带来异常路径更高的执行时间比在成功的道路。 这是不是与雨燕2.0个错误,其中的成功路径和错误路径的成本大约相同的情况下。
  • 所有的错误代码投掷必须声明,而例外可能是从任何地方抛出。 所有错误都用Java命名“检查的异常”。 然而,与去渣,不指定可能引发的错误。
  • 斯威夫特的例外是不ObjC例外兼容。 你do-catch块不会赶上任何NSException,反之亦然,对于必须使用ObjC。
  • 迅速的例外是用可可兼容NSError返回的方法公约或者false (为Bool返回功能)或nil (用于AnyObject返回功能)并传递NSErrorPointer与错误详细信息。

作为一个额外的syntatic糖来缓解错误处理,有两个概念

  • 递延行动(使用defer这让你达到同样的效果,最后用Java / C#的/ etc块关键字)
  • 后卫声明(使用guard关键字),它让你写的if / else代码比正常的错误检查/信令代码少一点。

斯威夫特1

运行时错误:

至于Leandros提出了处理运行时错误(如网络连接问题,解析数据,打开文件等),你应该使用NSError就像你在ObjC做,因为基金会了AppKit,UIKit的,等等这样报告其错误。 所以它更框架的东西不是语言的东西。

正被使用的另一种常见的图案是分离器的成功/失败的块等在AFNetworking:

var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
    success: { (NSURLSessionDataTask) -> Void in
        println("Success")
    },
    failure:{ (NSURLSessionDataTask, NSError) -> Void in
        println("Failure")
    })

仍是不良区频频接到NSError例如,描述错误。

编程错误:

对于程序员的错误(如出数组元素传递给函数调用的参数无效等的界限访问)您使用ObjC例外。 雨燕语言似乎并不有异常(如任何语言支持throwcatch等关键字)。 然而,随着文件表明,它是在同一个运行时作为ObjC运行,因此,你仍然可以扔NSExceptions是这样的:

NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()

你就不能赶上他们在纯斯威夫特,虽然你可能会选择在ObjC代码捕获异常。

问题是,你是否应该抛出异常的程序员错误,或者更确切地说,使用断言苹果暗示语言指南中。



Answer 2:

更新2015年6月9日-非常重要

雨燕2.0自带trythrow ,并catch关键词和最令人兴奋的是:

雨燕自动转换产生的误差成扔根据斯威夫特的本地错误处理功能的错误方法Objective-C的方法。

注:消耗的错误,如委托方法,或者采取与NSError对象参数完成处理方法的方法,不会成为当斯威夫特进口抛出方法。

摘自:苹果公司“使用斯威夫特与可可和Objective-C(斯威夫特2预发行)”的iBooks。

例如:(从书)

NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success && error){
    NSLog(@"Error: %@", error.domain);
}

在迅速等效为:

let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("path/to/file")
do {
    try fileManager.removeItemAtURL(URL)
} catch let error as NSError {
    print ("Error: \(error.domain)")
}

抛出一个错误:

*errorPtr = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotOpenFile userInfo: nil]

将自动传播给调用者:

throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo: nil)

从苹果的书籍,雨燕编程语言这似乎错误应该是处理使用枚举。

这是一本书的例子。

enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
case let .Result(sunrise, sunset):
    let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
    let serverResponse = "Failure...  \(error)"
}

来源:苹果公司“雨燕编程语言。”的iBooks。 https://itun.es/br/jEUH0.l

更新

苹果新闻的书籍,“使用斯威夫特与可可和Objective-C”。 运行时异常不会发生使用SWIFT的语言,所以这就是为什么你没有的try-catch。 而是使用可选链接 。

下面是从书中片段:

例如,在下面的代码列表中,第一和第二行不执行,因为长度属性和characterAtIndex:方法不一个NSDate对象上存在。 所述myLength常数推断为一个可选的中等,并且被设置为零。 你也可以使用一个if语句可以有条件地打开那三个行显示的对象可能不响应,方法的结果

let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)
if let fifthCharacter = myObject.characterAtIndex(5) {
    println("Found \(fifthCharacter) at index 5")
}

摘自:苹果公司“使用斯威夫特与可可和Objective-C”的iBooks。 https://itun.es/br/1u3-0.l


而且本本还鼓励您使用的Objective-C的(NSError对象)可可错误模式

在斯威夫特错误报告如下它在Objective-C相同的模式,以提供可选的返回值的额外好处。 最简单的例子,你从函数返回一个布尔值来表明它是否成功。 当您需要报告,查找错误的原因,你可以添加到功能型NSErrorPointer的NSError out参数。 这种类型大致相当于Objective-C的NSError **,额外内存的安全性和可选的输入。 可以使用前缀操作员在参考到可选NSError类型作为NSErrorPointer对象传递,如图中的代码下面的清单。

var writeError : NSError?
let written = myString.writeToFile(path, atomically: false,
    encoding: NSUTF8StringEncoding,
    error: &writeError)
if !written {
    if let error = writeError {
        println("write failure: \(error.localizedDescription)")
    }
}

摘自:苹果公司“使用斯威夫特与可可和Objective-C”的iBooks。 https://itun.es/br/1u3-0.l



Answer 3:

有斯威夫特没有例外,类似Objective-C的方法。

在开发中,你可以使用assert捕捉可能出现的任何错误,并需要才去生产加以固定。

经典NSError方法没有改变,您发送NSErrorPointer ,这被填充。

简单的例子:

var error: NSError?
var contents = NSFileManager.defaultManager().contentsOfDirectoryAtPath("/Users/leandros", error: &error)
if let error = error {
    println("An error occurred \(error)")
} else {
    println("Contents: \(contents)")
}


Answer 4:

推荐“雨燕路”是:

func write(path: String)(#error: NSErrorPointer) -> Bool { // Useful to curry error parameter for retrying (see below)!
    return "Hello!".writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: error)
}

var writeError: NSError?
let written = write("~/Error1")(error: &writeError)
if !written {
    println("write failure 1: \(writeError!.localizedDescription)")
    // assert(false) // Terminate program
}

不过我更喜欢的try / catch,因为我觉得它更容易执行,因为它在最后移动错误处理到一个单独的块,这样的安排有时被称为“黄金路”。 幸运的你可以用瓶盖做:

TryBool {
    write("~/Error2")(error: $0) // The code to try
}.catch {
    println("write failure 2: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

也很容易添加一个重试设施:

TryBool {
    write("~/Error3")(error: $0) // The code to try
}.retry {
    println("write failure 3 on try \($1 + 1): \($0!.localizedDescription)")
    return write("~/Error3r")  // The code to retry
}.catch {
    println("write failure 3 catch: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

对于TryBool上市是:

class TryBool {
    typealias Tryee = NSErrorPointer -> Bool
    typealias Catchee = NSError? -> ()
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return self.retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) {
        var error: NSError?
        for numRetries in 0...retries { // First try is retry 0
            error = nil
            let result = tryee(&error)
            if result {
                return
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        catchee(error)
    }
}

你可以写一个类似的类测试可选的返回值,而不是布尔值:

class TryOptional<T> {
    typealias Tryee = NSErrorPointer -> T?
    typealias Catchee = NSError? -> T
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) -> T {
        var error: NSError?
        for numRetries in 0...retries {
            error = nil
            let result = tryee(&error)
            if let r = result {
                return r
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        return catchee(error)
    }
}

该TryOptional版本强制非可选返回类型,使得后续的编程更简单,如“斯威夫特方式:

struct FailableInitializer {
    init?(_ id: Int, error: NSErrorPointer) {
        // Always fails in example
        if error != nil {
            error.memory = NSError(domain: "", code: id, userInfo: [:])
        }
        return nil
    }
    private init() {
        // Empty in example
    }
    static let fallback = FailableInitializer()
}

func failableInitializer(id: Int)(#error: NSErrorPointer) -> FailableInitializer? { // Curry for retry
    return FailableInitializer(id, error: error)
}

var failError: NSError?
var failure1Temp = failableInitializer(1)(error: &failError)
if failure1Temp == nil {
    println("failableInitializer failure code: \(failError!.code)")
    failure1Temp = FailableInitializer.fallback
}
let failure1 = failure1Temp! // Unwrap

使用TryOptional:

let failure2 = TryOptional {
    failableInitializer(2)(error: $0)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

let failure3 = TryOptional {
    failableInitializer(3)(error: $0)
}.retry {
    println("failableInitializer failure, on try \($1 + 1), code: \($0!.code)")
    return failableInitializer(31)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

注意自动解包。



Answer 5:

编辑:尽管这个答案的作品,它是多一点的Objective-C音译为斯威夫特。 它已经在雨燕2.0已经作废的变化。 上面的Guilherme托雷斯卡斯特罗的回答是一个很好的介绍,在斯威夫特错误处理的首选方式。 VOS

它采取了一些计算出来的,但我想我已经sussed它。 这似乎丑陋虽然。 没有什么比一个薄的皮肤在Objective-C的版本更多。

调用带有一个NSError参数的函数...

var fooError : NSError ? = nil

let someObject = foo(aParam, error:&fooError)

// Check something was returned and look for an error if it wasn't.
if !someObject {
   if let error = fooError {
      // Handle error
      NSLog("This happened: \(error.localizedDescription)")
   }
} else {
   // Handle success
}`

编写需要一个误差参数的功能...

func foo(param:ParamObject, error: NSErrorPointer) -> SomeObject {

   // Do stuff...

   if somethingBadHasHappened {
      if error {
         error.memory = NSError(domain: domain, code: code, userInfo: [:])
      }
      return nil
   }

   // Do more stuff...
}


Answer 6:

围绕目标C基本包装,让您尝试捕捉功能。 https://github.com/williamFalcon/SwiftTryCatch

使用这样的:

SwiftTryCatch.try({ () -> Void in
        //try something
     }, catch: { (error) -> Void in
        //handle error
     }, finally: { () -> Void in
        //close resources
})


Answer 7:

这是SWIFT 2.0更新的答案。 我期待着功能丰富的错误处理模型像Java中。 最后,他们宣布了这个好消息。 这里

错误处理模型:在雨燕2.0的新的错误处理模式将立刻感到自然,与熟悉的尝试,throw和catch关键字 。 最重要的是,它被设计为与苹果的SDK和NSError很好地工作。 事实上,NSError符合一个斯威夫特的错误类型。 你一定会想观看关于在斯威夫特的新听到更多关于它的WWDC会议。

例如:

func loadData() throws { }
func test() {
do {
    try loadData()
} catch {
    print(error)
}}


Answer 8:

作为吉列尔梅托雷斯卡斯特罗说,在雨燕2.0, trycatchdo可以在编程中使用。

例如,在CoreData获取数据的方法,而不是放&error作为一个参数到managedContext.executeFetchRequest(fetchRequest, error: &error) ,现在我们只需要使用使用managedContext.executeFetchRequest(fetchRequest)然后用处理错误trycatch ( 苹果文档链接 )

do {
   let fetchedResults = try managedContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
   if let results = fetchedResults{
      people = results
   }
} catch {
   print("Could not fetch")
}

如果您已经下载了xcode7 Beta版。 试着在搜索文档和API参考 引发错误 ,并选择先显示结果,它给出了一个基本的想法我能为这个新的语法来完成。 然而,完全的文档没有张贴许多API还没有。

更看中的错误处置技术可发现

在斯威夫特最新消息(2015届106 28m30s)



Answer 9:

错误处理是雨燕2.0的新特性。 它采用了trythrowcatch关键词。

看到在苹果官方博客雨燕雨燕苹果宣布2.0



Answer 10:

斯威夫特有2起,正如其他人已经提到的,错误处理,最好通过使用DO的完成/ try / catch语句和错误类型枚举。 这工作得很好的同步方法,但需要异步错误处理的一个小聪明。

这篇文章有一个伟大的方式解决这个问题:

https://jeremywsherman.com/blog/2015/06/17/using-swift-throws-with-completion-callbacks/

总结:

// create a typealias used in completion blocks, for cleaner code
typealias LoadDataResult = () throws -> NSData

// notice the reference to the typealias in the completionHandler
func loadData(someID: String, completionHandler: LoadDataResult -> Void)
    {
    completionHandler()
    }

然后,调用上述方法将如下所示:

self.loadData("someString",
    completionHandler:     
        { result: LoadDataResult in
        do
            {
            let data = try result()
            // success - go ahead and work with the data
            }
        catch
            {
            // failure - look at the error code and handle accordingly
            }
        })

这似乎比具有传递给异步函数,这是如何做到这一点之前夫特2进行处理的单独的ErrorHandler回调吸尘器的位。



Answer 11:

我所看到的是,由于设备的性质,你不希望在用户被扔了一堆神秘的错误消息的处理。 这就是为什么大多数函数返回可选值,那么你只代码忽略可选。 如果一个函数回来零意味着失败,你可以弹出一个消息或什么的。



Answer 12:

尼斯和简单的LIB处理异常: TryCatchFinally -斯威夫特

像其他一些它环绕的客观C异常特征。

使用这样的:

try {
    println("  try")
}.catch { e in
    println("  catch")
}.finally {
    println("  finally")
}


文章来源: Error-Handling in Swift-Language