为了账号安全,请及时绑定邮箱和手机立即绑定

Swift中处理可选变量访问和类型转换时的异常技巧

标签:
Swift

AI生成的图

作为一名拥有Java和Kotlin背景的Android开发者,不得不说这些JVM语言中的错误处理非常出色。几乎可以处理任何类型的异常

然而,我对其他语言,尤其是Swift,就不能这么说,虽然我有一些使用Swift的经验。目前,我正在使用React Native工作,经常需要切换到原生代码。最近,我发现了一个在Swift中非常有趣的现象,想跟大家分享一下。

访问变量

让我们来写一个简单的原生模块,以一种不安全的方式访问变量中的值,并看看Android和iOS是如何处理这种情况的。之后,我们再来看看怎么解决这个问题。

安卓

这是一个简单的原生函数,每次调用时,因为我们在访问一个空变量时使用了空断言,它会抛出NPE(空指针异常)异常。try-catch块完成了任务并处理了异常。

        @ReactMethod  
        fun unsafeAccess(promise: Promise) {  
            // 尝试执行操作
            try {  
                // 定义一个可能为null的整数变量
                val value: Int? = null  
                // 尝试将可能为null的变量与10相加
                val sum = value!! + 10  
                // 如果操作成功,则解析结果
                promise.resolve(sum)  
            } catch (e: Exception) {  
                // 如果操作失败,则拒绝解析
                promise.reject(e)  
            }  
        }
iOS(苹果操作系统)

我们也可以这样在 Swift 里写类似的内容。

// 安全访问方法,接收两个回调函数,resolve和reject。在执行过程中,如果成功则通过resolve返回结果,如果失败则通过reject返回错误。
@objc func unsafeAccess(_ resolve: RCTPromiseResolveBlock, _ reject: RCTPromiseRejectBlock) {
  do {
    let value: Int? = nil
    let sum = value! + 10
    resolve(sum)
  } catch {
    reject(nil, nil, error)
  }
}

如果我们调用这个函数的话,你觉得会发生什么?异常会被捕获块处理吗?应该可以处理,对吧?但实际上,这可能会导致应用崩溃,你可能会觉得意外。

我觉得这很有趣。Xcode 会提示你,这里的 catch 块实际上没有做任何事情。这在 Swift 开发者中并不新鲜,但是在你切换语言时,这种行为可能会让你感到意外。

你可以在这里找到更多信息:here

类型转换 (Type Casting)

让我们试着写一个这样的不安全的类型转换函数,并比较它在Android和iOS上的差异。

安卓
        @ReactMethod  
        fun 不安全转换(promise: Promise) {  
            try {  
                // 尝试将整数转换为字符串
                val 值: Int = 10  
                val 转换后的值: String = 值 as String  
                promise.解决(转换后的值)  
            } catch (e: Exception) {  
                promise.拒绝(e)  
            }  
        }

和之前一样,Android 捕获了异常信息。

iOS
      // 定义一个名为 unsafeCast 的方法,它接受两个参数:resolve 和 reject,这两个参数分别是解决块和拒绝块。
      @objc func unsafeCast(  
        _ resolve: RCTPromiseResolveBlock, _ reject: RCTPromiseRejectBlock  
      ) {  
        // 使用 do-catch 结构来处理可能的异常。
        do {  
          // 初始化一个整数值 value,值为 10。
          let value: Int = 10  
          // 尝试将 value 进行不安全强制转换为字符串类型。
          let castValue: String = value as! String  
          // 如果转换成功,则使用 resolve 块返回转换后的值。
          resolve(castValue)  
        } catch {  
          // 如果在转换过程中出现错误,则使用 reject 块返回错误信息。
          reject(nil, nil, error)  
        }  
      }

这种不安全的类型转换操作会在运行时抛出异常,并就像以前那样导致应用崩溃。

解决办法

可以说我们有 _if-let__guard-let_ 来处理这些情况,我也同意使用它们。然而,在使用 React Native 时,你无法确定 JS 方面会发送什么内容,所以使用 _if-let__guard-let_ 会使代码变得冗长且难以阅读,影响可读性。

一个简单的解决办法是创建一个工具函数,用来在遇到问题时抛出异常而不是让应用程序崩溃。下面有两个函数,一个是用来处理可选类型,另一个是用于类型转换。你可以用它们。

    // 安全解包可选值的工具函数
    func unwrap<T>(  
        _ optional: T?,  
        errorMessage _: String = "解包失败"  
    ) throws -> T {  
        guard let value = optional else {  
            throw NSError(domain: "unwrap error", code: 2)  
        }  
        return value  
    }  

    // 安全转换可选值的工具函数
    func cast<T>(  
        _ value: Any?,  
        to _: T.Type,  
        errorMessage _: String = "转换失败"  
    ) throws -> T {  
        guard let castedValue = value as? T else {  
            throw NSError(domain: "cast error", code: 3)  
        }  
        return castedValue  
    }

这就是使用该函数的方法。

      @objc func safeAccess(  
        _ resolve: RCTPromiseResolveBlock, _ reject: RCTPromiseRejectBlock  
      ) {  
        // 安全访问函数,尝试解包值并处理错误
        do {  
          let value: Int? = nil // 定义一个可选整数变量值,初始值为nil
          let sum = try unwrap(value) + 10 // 尝试解包值并加上10
          resolve(sum)  
        } catch {  
          reject(nil, nil, error) // 如果发生错误,则调用reject方法并传递错误信息
        }  
      }  

      @objc func safeCast(  
        _ resolve: RCTPromiseResolveBlock, _ reject: RCTPromiseRejectBlock  
      ) {  
        // 安全转换函数,尝试将值转换为字符串类型
        do {  
          let value: Int = 10  
          let castValue: String = try cast(value, to: String.self) // 尝试将值转换为String类型
          resolve(castValue)  
        } catch {  
          reject(nil, nil, error) // 如果发生错误,则调用reject方法并传递错误信息
        }  
      }

如你所见,这不会让应用崩溃,而且还很好地处理了异常。

你可以在这里找到源代码哦。

GitHub - susonthapa/rn-automatic-data-parser at exception-handling-ios展示如何将JavaScript对象转换为原生对象,反之亦然 - GitHub …github.com

行了,这可真快。希望你学到了新东西。再见。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消