使用 NSExpression 时捕获 NSInvalidArgumentException 的正确方法 [重复]
Posted
技术标签:
【中文标题】使用 NSExpression 时捕获 NSInvalidArgumentException 的正确方法 [重复]【英文标题】:Correct way to catch NSInvalidArgumentException when using NSExpression [duplicate] 【发布时间】:2017-04-24 10:19:39 【问题描述】:我想验证用户创建的表达式(例如“2+2”、“5+7”或更复杂的表达式)。我使用 NSExpression 类来解析和计算这个表达式。这是我的游乐场代码:
import UIKit
let string = "2+2"
var ex:NSExpression?
do
ex = NSExpression(format: string)
catch
print("String is not valid expression")
if let result = ex?.expressionValue(with: nil, context: nil) as! NSNumber?
print("result is \(result)")
当我使用有效的表达式 ("2+2") - 我得到结果。但有时用户可能会提供错误的字符串(例如“2+”)。使用此字符串,我的应用程序会因此崩溃:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "2+ == 1"'
我不明白如何捕获这个异常以及为什么上面的代码不这样做。现在我使用 Objective C 类(具有相同的逻辑),从我的 swift 代码中调用这个方法,在那个类中我真的可以捕捉到这样的异常:
+(NSNumber *)solveExpression:(NSString *)string
id value;
@try
NSExpression *ex = [NSExpression expressionWithFormat:string];
value = [ex expressionValueWithObject:nil context:nil];
@catch (NSException *e)
return value;
这行得通,我可以获得正确的解析状态(nil 表示表达式有问题)和结果(NSNumber),但我真的很想了解如何在 Swift 中完全正确地完成所有这些事情。
【问题讨论】:
试试***.com/a/54998045/3908884 【参考方案1】:NSInvalidArgumentException
不是 Java 异常意义上的可捕获错误。 Apple 不保证当您捕获此异常时您的程序将处于正确状态,并且很可能会出现问题。
在将字符串传递给方法之前,您可能应该使用其他一些机制来检查字符串是否有效。
【讨论】:
谢谢。看起来使用支持“表达式验证”的库会更好,而不仅仅是“表达式求解”。现在我在看github.com/davedelong/DDMathParser【参考方案2】:这就是Using Swift with Cocoa and Objective-C这本书的内容has to say:
虽然 Swift 错误处理类似于 Objective-C 中的异常处理,但它是完全独立的功能。如果 Objective-C 方法在运行时抛出异常,Swift 会触发运行时错误。 没有办法直接在 Swift 中从 Objective-C 异常中恢复。任何异常处理行为都必须在 Swift 使用的 Objective-C 代码中实现。
[我的粗体]
刚刚浏览了NSExpression
的参考资料,我看不出解决这个问题的简单方法。上面的引用建议编写一些 Objective-C 代码来完成它。最简单的方法可能是创建一个 C 函数:
声明:
extern NSExpression* _Nullable makeExpression(NSString* format _Nonnull);
定义
NSExpression* _Nullable makeExpression(NSString* format _Nonnull)
NSExpression* ret = nil;
@try
// create and assign the expression to ret
@catch(NSException* e)
// ignore
return ret;
函数对错误的表达式返回 nil。
您可能会添加一个NSError**
参数以在出现故障时使用。您也可以在NSExpression
上将其设为一个类别中的方法,然后错误/填充 NSError 模式的返回 nil 可能会作为 Swift 抛出方法导入到 Swift。
顺便说一句,我应该说,Objective-C 异常并不能真正保证让您的程序处于一致状态。在这种情况下,手指交叉是可以的。
【讨论】:
以上是关于使用 NSExpression 时捕获 NSInvalidArgumentException 的正确方法 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
从 NSExpression 捕获 NSInvalidArgumentException
NSExpression 使用 sqrt: 函数导致 NSInvalidArgumentException
我可以强制 NSExpression 和 expressionValue 以某种方式假设 Doubles 而不是 Ints 吗?
在 iOS 6.0 和 iOS 6.0.1 上调用 [FBSession openActiveSessionWithPermissions...] 时从 ACAccountStore 抛出 NSInv