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行了,这可真快。希望你学到了新东西。再见。
共同学习,写下你的评论
评论加载中...
作者其他优质文章