使用NSExpression时捕获NSInvalidArgumentException的正确方法

时间:2017-04-24 10:19:40

标签: swift exception-handling nsexpression objective-c-swift-bridge

我想验证用户创建的表达式(例如“2 + 2”,“5 + 7”或更复杂)。我使用NSExpression类来解析和计算这个表达式。这是我的Playground代码:

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中正确完成所有这些事情。

2 个答案:

答案 0 :(得分:3)

本书使用Swift与Cocoa和Objective-C empty pseudo class

  

尽管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异常并不能保证让你的程序保持一致状态。在这种情况下,手指越过它是可以的。

答案 1 :(得分:2)

从Java异常的意义上来说,

NSInvalidArgumentException不是一个可捕获的错误。当你发现这个异常时,Apple并不能保证你的程序处于正确的状态,并且可能会出现问题。

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