web-dev-qa-db-ja.com

SwiftはObjective-CNSError **をスローに変換しません

私はいくつかの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"メソッドに変換するためにさらに何かが必要ですか?

23
Anton Tyutin

BOOLまたは(nullable)オブジェクトを返すObjective-Cメソッドのみが、Swiftのスローメソッドに変換されます。

その理由は、Cocoaメソッドは常にメソッドの失敗を示すために戻り値NOまたはnilを使用し、notエラーを設定するだけだからです。オブジェクト。これは エラーオブジェクトの使用と作成 に記載されています:

重要:成功または失敗は、メソッドの戻り値によって示されます。 Cocoaエラードメイン内のエラーオブジェクトを間接的に返すCocoaメソッドは、メソッドが直接nilまたはNOを返すことによって失敗を示した場合、そのようなオブジェクトを返すことが保証されていますが、 NSErrorオブジェクト。

たとえば、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 asにマップされます

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 as as

public func doSomethingWithArgument5(x: Int32) throws

そして、「期待どおりに」動作するようです。ただし、この属性に関する公式のドキュメントが見つからなかったため、これに依存するのは得策ではないかもしれません。

37
Martin R

エラーをスローするかどうかをランタイムに通知するには、メソッドにBOOLを返すようにする必要があります。また、エラーパラメータに__autoreleasingを追加して、使用する前にARCが誤ってエラーを解放しないようにする必要があります。

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

次に、Swiftからこのように呼び出すことができます:

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