try? 语法的优点在于你不必把可能会抛出错误的函数写在一个 do-catch 代码块当中。如果你使用了 try?,该函数的返回值就会是一个可选类型:成功返回 .some,失败则返回 .None。你可以配合着 if-let 或者 guard 语句来使用 try? 语法。

try? 语法的不足则在于它对错误的简化,让你难以了解到错误是什么以及错误发生的时间。这可不是件好事。

但你可以试着写出 try? 的替代方法。比如一个简单的结果枚举:

enum Result<T> {
    case Value(T)
    case Error(ErrorType)
}

就像上面的代码写的那样,我喜欢分成 ValueError 而不是 errok ,枚举的不同状态可以按你自己的喜好来命名。然后你可以写个函数用 do-catch 语句给你枚举类型的结果做个封装然后返回。

func tryit<T>(block: () throws -> T) -> Result<T> {
    do {
        let value = try block()
        return Result.Value(value)
    } catch {return Result.Error(error)}
}

实际上我也不太喜欢 tryit 这个名字,你用你喜欢的名字代替就好。这个函数的调用有点啰嗦了,不是我们想要的这样:

let result = try myFailableCoinToss()

而是这种:

let result = tryit(myFailableCoinToss)

一位名叫 glessard 的读者提供给我了另一种替代方式,建议我给 Result 添加一个初始化方法而不是用 tryit:

enum Result<T> {
    case Value(T)
    case Error(ErrorType)

    init(_ block: () throws -> T) {
        do {
            let value = try block()
            self = Result.Value(value)
        } catch {
            self = Result.Error(error)
        }
    }
}

然后你直接这么调用就行了:

let result = Result(myFailableCoinToss)

如果你要用 if-letguard 之外的语句来拆包你的返回值,可以用 switch

let result = tryit(myFailableCoinToss)
switch result {
case .Value(let value): print("Success:",value)
case .Error(let error): print("Failure:",error)
}

或者直接用模式匹配:

if case .Value(let value) = result {
    print("Success:",value)
} else if case .Error(let error) = result {
    print("Failure:",error)
}

你也可以添加一些退出作用域的代码来模仿 guard,这的确可行,但是代码太难看了。

enum Result<T> {
    case Value(T)
    case Error(ErrorType)

    func unwrap() throws -> T {
        if case .Value(let value) = self {return value}
        throw "Unable to unwrap result"
    }

    func handleError(errorHandler: ErrorType -> Void) -> Bool {
        if case .Error(let error) = self {
            errorHandler(error)
            return true
        }
        return false
    }
}

func tryit<T>(block: () throws -> T) -> Result<T> {
    do {
        let value = try block()
        return Result.Value(value)
    } catch {return Result.Error(error)}
}

let result = tryit(myFailableCoinToss)

// guard error
if result.handleError({
    error in
    print("Error is \(error)")
}) {fatalError()} // leave scope on true

// force try for success case
let unwrappedResult = try! result.unwrap()

// result is Now usable at top level scope
print("Result is \(unwrappedResult)")

这还有另外一种更像 try? 的方式,但是至少打印了错误。

func tryit<T>(block: () throws -> T) -> Optional<T>{
    do {
        return try block()
    } catch {
        print(error)
        return nil
    }
}

第二种替代 try? 的方法不仅拥有了 if-letguard 的语句特性,还能返回错误。你可以以同样的方法调用它:

let result = tryit(myFailableCoinToss)

你仍然不能基于错误类型和错误细节来制定错误处理策略,但是这种实现方式也不像 try? 那样把错误信息完全丢弃掉了。

你也可以修改 tryit 函数,让它也能接受做错误处理的代码块,但因为要处理两种不同的代码块,这个函数就会变得相当臃肿。我尝试过几种不同的实现方式,但都做的不太好,就不在这分享出来了。最大的问题是,就算你把做错误处理的代码块传给 tryit 了,你也不能像 guard 语句那样退出作用域,而且也没有这样的 guard 的替代形式能接受 try? 的 error 来作退出作用域代码块的参数。

我觉得我最后实现的应该类似于下面的这种形式,在顶层作用域中执行条件赋值,并采用 guard 语句的方式来替代普通的 try

guard let result = try!! myFailableCoinToss() else {error in ...}

之所以这么做是因为我们想知道我们的程序到底会不会出错,如果不出错的话,直接就能得到返回值了。

let result = try myFailableCoinToss()

如果要用 try 而且又需要进行错误处理的话,你就必须得用 do-catch 或者像结果枚举之类的其它方法了。

Swift 2.0 try? 的替代方法的更多相关文章

  1. ios – 我可以安全地在@try catch块中包装’CoreData无法解决错误’错误

    )是的,我偶尔会得到’CoreData无法完成故障’的错误.在我的特定应用程序中,这通常发生在一种“数据绑定”过程中,因此我可以安全地丢弃故障对象并继续前进.我想通过在@try-catch块中包装数据绑定的循环内部并且只跳过我得到CoreData错误的行来完成此操作.我可以使用CoreData安全地执行此操作吗?

  2. 你如何压缩iOS上的Realm DB?

    我想定期在iOS上压缩一个Realm实例来恢复空间.我认为该过程是将数据库复制到临时位置,然后将其复制回来并使用新的default.realm文件.我的问题是Realm()就像一个单例并且回收对象,所以我无法真正关闭它并告诉它打开新的default.realm文件.这里的文档(https://realm.io/docs/objc/latest/api/Classes/RLMRealm.html)建

  3. ios – 捕获NSKeyedUnarchiver异常

    在Swift中,如果无法取消存档数据,NSKeyedUnarchiver.unarchiveObjectWithData(data)将抛出异常.在某些情况下,我们无法保证数据是否未损坏,例如从文件读取时.我不知道Swift中的try/catch机制,也不知道像canUnarchive这样有助于防止异常的方法.除了在Obj-C中实现try/catch之外,还有一个纯Swift解决方案来解决这个问题吗

  4. ios – 使用swift进行异常处理

    catch来处理它.如果故事板中没有视图控制器,则无法执行任何操作.这是程序员的错误,创建它的人应该处理这些问题.你不能因为这种错误而责怪iOS运行时.

  5. ios – Swift 3 – 将文件夹从主包复制到文档目录

    我的主要包中包含文件夹,我想在首次启动应用程序时将它们复制/剪切到文档目录,以便从那里访问它们.我见过一些例子,但他们都在Obj-C中,我正在使用Swift3.我怎么能这样做?解决方法我设法使用2个功能:

  6. Swift 2.0 try? 的替代方法

    你可以配合着if-let或者guard语句来使用try?但你可以试着写出try?实际上我也不太喜欢tryit这个名字,你用你喜欢的名字代替就好。你可以以同样的方法调用它:你仍然不能基于错误类型和错误细节来制定错误处理策略,但是这种实现方式也不像try?你也可以修改tryit函数,让它也能接受做错误处理的代码块,但因为要处理两种不同的代码块,这个函数就会变得相当臃肿。如果要用try而且又需要进行错误处理的话,你就必须得用do-catch或者像结果枚举之类的其它方法了。

  7. The Swift Programming Language 翻译 —— 错误处理

    Swift支持抛出、捕获、传递和操作等四种方式来处理程序运行时出现的可恢复性错误。表示错误类型在Swift中,错误类型用继承了ErrorType协议的类型来表示。Swift中处理错误的方式有如下四种:使用throw关键字继续向上传递这个错误、使用do-catch表达式处理这个错误、使用try?下面例子中的buyFavoriteSnack方法调用了vend方法,任何vend方法抛出的错误都将传递给他,他选择继续向上传递这些错误。x和y的类型是someThrowingFunction()的返回值类型对应的可选

  8. Swift 2 jSON Call can throw but it is not marked with try

    NSDictionary第一种用法:第二种用法:letjsonData=tryNSJSONSerialization.JSONObjectWithData(urlData!

  9. Swift2.0提供所try catch异常捕捉

    原代码中,AVAudioPlayer的构造函数有了可抛出错误的重载函数,现在的原型不接受第二个error参数,函数不再为failable,应使用trycatch捕捉异常

  10. Swift 读取本地json文件时的异常捕获(try catch)的使用

    Swift读取本地json文件时的异常捕获(trycatch)的使用

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部