I have some Objective-C legacy code, that declares method like
- (void)doSomethingWithArgument:(ArgType)argument error:(NSError **)error
As written here https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html
Swift automatically translates Objective-C methods that produce errors into methods that throw an error according to Swift’s native error handling functionality.
But in my project described methods are called like this:
object.doSomething(argument: ArgType, error: NSErrorPointer)
Moreover, it throws runtime exception when I try to use them like:
let errorPtr = NSErrorPointer()
object.doSomething(argumentValue, error: errorPtr)
Do I need something more to convert Objective-C "NSError **" methods to Swift "trows" methods?
Only Objective-C methods which return a BOOL
or a (nullable) object
are translated to throwing methods in Swift.
The reason is that Cocoa methods always use a return value NO
or nil
to indicate the failure of a method, and not just set an error object.
This is documented in
Using and Creating Error Objects:
Important: Success or failure is indicated by the return value of the method. Although Cocoa methods that indirectly return error objects in the Cocoa error domain are guaranteed to return such objects if the method indicates failure by directly returning nil or NO, you should always check that the return value is nil or NO before attempting to do anything with the NSError object.
For example, the Objective-C interface
@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
is mapped to 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
}
If you can change the interface of your method then you should add a boolean return value to indicate success or failure.
Otherwise you would call it from Swift as
var error : NSError?
object.doSomethingWithArgument(argumentValue, error: &error)
if let theError = error {
print(theError)
}
Remark: At
I found that Clang has an attribute which forces a function to throw an error in Swift:
-(void)doSomethingWithArgument5:(int) x error:(NSError **)error
__attribute__((swift_error(nonnull_error)));
is mapped to Swift as
public func doSomethingWithArgument5(x: Int32) throws
and seems to work "as expected". However, I could not find any official documentation about this attribute, so it might not be a good idea to rely on it.