Swift不会将Objective-C NSError **转换为throws

时间:2016-01-14 09:40:47

标签: ios objective-c swift nserror

我有一些Objective-C遗留代码,声明类似

的方法
- (void)doSomethingWithArgument:(ArgType)argument error:(NSError **)error

正如此处所写https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html

  

Swift自动转换产生错误的Objective-C方法   根据Swift的本机错误抛出错误的方法   处理功能。

但是在我的项目中描述的方法被称为:

object.doSomething(argument: ArgType, error: NSErrorPointer)

此外,当我尝试使用它们时会抛出运行时异常:

let errorPtr = NSErrorPointer()
object.doSomething(argumentValue, error: errorPtr)

我是否需要更多东西来将Objective-C“NSError **”方法转换为Swift“trows”方法?

2 个答案:

答案 0 :(得分:31)

只返回BOOL或(可为空)对象的Objective-C方法 被转换为Swift中的抛出方法。

原因是Cocoa方法总是使用返回值NOnil 指示方法失败,只设置错误对象。 这是记录在案 Using and Creating Error Objects

  

重要提示:方法的返回值表示成功或失败。   虽然Cocoa方法间接返回Cocoa错误中的错误对象   如果方法指示失败,则保证域返回此类对象   通过直接返回nil或NO,你应该经常检查返回   在尝试对NSError对象执行任何操作之前,value为nil或NO。

例如,Objective-C接口

@interface OClass : NSObject

NS_ASSUME_NONNULL_BEGIN

-(void)doSomethingWithArgument1:(int) x error:(NSError **)error;
-(BOOL)doSomethingWithArgument2:(int) x error:(NSError **)error;
-(NSString *)doSomethingWithArgument3:(int) x error:(NSError **)error;
-(NSString * _Nullable)doSomethingWithArgument4:(int) x error:(NSError **)error;

NS_ASSUME_NONNULL_END

@end

映射到Swift为

public class OClass : NSObject {

    public func doSomethingWithArgument1(x: Int32, error: NSErrorPointer)
    public func doSomethingWithArgument2(x: Int32) throws
    public func doSomethingWithArgument3(x: Int32, error: NSErrorPointer) -> String
    public func doSomethingWithArgument4(x: Int32) throws -> String
}

如果您可以更改方法的界面,那么您应该添加一个布尔值 返回值表示成功或失败。

否则你会从Swift中调用它

var error : NSError?
object.doSomethingWithArgument(argumentValue, error: &error)
if let theError = error {
    print(theError)
}

备注:

我发现Clang有一个强制函数在Swift中抛出错误的属性:

-(void)doSomethingWithArgument5:(int) x error:(NSError **)error
  __attribute__((swift_error(nonnull_error)));

映射到Swift为

public func doSomethingWithArgument5(x: Int32) throws

似乎按预期工作。但是,我找不到任何官方文件 关于这个属性,所以依靠它可能不是一个好主意。

答案 1 :(得分:2)

您需要让方法返回BOOL,告诉运行时应该或不应该抛出错误。另外,您应该将__autoreleasing添加到错误参数中,以确保ARC在您有机会使用错误之前不会意外释放错误:

- (BOOL)doSomethingWithArgument:(ArgType)argument error:(NSError * __autoreleasing *)error

然后你可以像这样从Swift中调用它:

do {
    object.doSomethingWithArgument(someArgument)
} catch let err as NSError {
    print("Error: \(err)")
}