5

我想验证用户创建的表达式(如“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 中正确地完成所有这些事情。

4

2 回答 2

3

NSInvalidArgumentException不是 Java 异常意义上的可捕获错误。当您捕获此异常时,Apple 不保证您的程序将处于正确状态,并且很可能会出现问题。

在将字符串传递给方法之前,您可能应该使用其他一些机制来检查字符串是否有效。

于 2017-04-24T10:30:25.853 回答
3

这就是《Using Swift with Cocoa and Objective-C 》这本书 所说的:

尽管 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**参数以在出现故障时使用。您也可以将其设置为 on 类别中的方法,NSExpression然后错误/填充 NSError 模式的返回 nil 可能会作为 Swift throwing 方法导入 Swift。

顺便说一句,我应该说,Objective-C 异常并不能真正保证让您的程序处于一致状态。在这种情况下,手指交叉是可以的。

于 2017-04-24T10:47:43.187 回答