On Sep 29, 2016, at 5:46 PM, Ronak via swift-users <swift-users@swift.org> wrote:
Ahh..thanks for the reply Zach. I didn’t actually see your reply until now.
I’ll see how I can adjust my code.
On Sep 29, 2016, at 4:38 PM, Zach Waldowski <zach@waldowski.me <mailto:zach@waldowski.me>> wrote:
Error types themselves shouldn’t generally cross into Objective-C, because you don’t get interop; for that, we have Error, which crosses the bridge as NSError.
If it’s instructive to think of it this way, both Objective-C and Swift should define errors in their best native way, and use NSError. That’s, at least, the use case for CustomNSError and LocalizedError.
If you’re primarily exporting errors from Objective-C to be “seen” in Swift, you want to look into the ns_error_domain attribute on the C side. This generates a good deal of the enum Code: Int boilerplate coming in to Swift, but it’s obnoxious to create those errors from Swift.
If you’re primarily exporting errors from Swift to Objective-C, you can make any Swift type implement Error and CustomNSError, which can then cross the bridge.
The happy path of full error interop in both directions is a little more complicated. Generally you have to start with one of the above approach and “mirror” some values in the other language. Consider the following as a slightly over-wrought example of having your cake and eating it too:
extern NSString *const MyErrorDomain NS_REFINED_FOR_SWIFT;
extern NSString *const MyErrorUserInfoStringKey NS_REFINED_FOR_SWIFT;
typedef NS_ENUM(NSInteger, MyErrorCode) {
MyErrorCodeOne,
MyErrorCodeTwo,
MyErrorCodeThree,
} NS_REFINED_FOR_SWIFT;
enum MyError: CustomNSError {
case one(String)
case two
case three
static var errorDomain: String {
return __MyErrorDomain
}
var errorCode: Int {
switch self {
case .one:
return __MyErrorCode.one.rawValue
case .two:
return __MyErrorCode.two.rawValue
case .three:
return __MyErrorCode.three.rawValue
}
}
var errorUserInfo: [String: Any] {
var userInfo = [String: Any]()
if case let .one(string) = self {
userInfo[__MyErrorUserInfoStringKey] = string
}
return userInfo
}
}
On Sep 29, 2016, at 1:17 PM, Ronak via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hello all,
We are proceeding to update all of our Swift code to Swift 3 now and had a few questions about the proper way to implement Errors. We need these entities to be available in Objective-C and they are actively being used in Swift classes marked as @objc.
I read: https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md completely and came up with this implementation:
/// The enumeration of the possible error codes in the Foundation error domain
@objc public class FoundationError: NSObject, CustomNSError {
/// The underlying error code
private let code: FoundationError.Code
/// The type of an error code.
@objc public enum Code: Int {
/// An ARCOperationCondition failed during evaluation
case operationConditionFailed = 10000
/// An ARCOperation failed during execution
case operationExecutionFailed = 10001
}
/// The domain of the error.
public static var errorDomain: String {
return "FoundationError"
}
/// The error code within the given domain.
public var errorCode: Int {
return code.rawValue
}
/// The user-info dictionary.
public let errorUserInfo: [String : Any]
/// Initializes a new FoundationError with an empty userInfo dictionary
///
/// - parameter code: one of the available error codes
///
/// - returns: a new instance of FoundationError
public convenience init(code: FoundationError.Code) {
self.init(code: code, userInfo: [:])
}
/// Initializes a new FoundationError with an userInfo dictionary
///
/// - parameter code: one of the available error codes
/// - parameter userInfo: the user-info dictionary
///
/// - returns: a new instance of FoundationError
public init(code: FoundationError.Code, userInfo: [String : Any]) {
self.code = code
errorUserInfo = userInfo
}
/// Computes whether two FoundationErrors are equal
///
/// - parameter object: a FoundationError
///
/// - returns: true, if the two errors are equal
public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? FoundationError else { return false }
return errorCode == object.errorCode && errorUserInfo.keys.elementsEqual(object.errorUserInfo.keys)
}
}
My question is whether this is the correct way to do this now; or is there another solution we should be doing? We would like to follow Swift Best Practices here, but unfortunately, the documentation is quite vague on this subject.
Thanks for your help!
Ronak Patel
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users