[swift-users] Proper Way to make Errors in Swift 3
Ronak
ronak2121 at yahoo.com
Thu Mar 2 10:29:23 CST 2017
Hi everyone,
It looks like I’m still having issues exposing a CustomNSError to Objective-C. I am generating errors of this type in Swift and then trying to bridge them in one direction over to Objective-C.
From Objective-C, this Error type is being exposed as a _SwiftValue.
Do I have to mark this error as @objc and switch to using a raw enum? If so, I fail to see the benefit of using CustomNSError or any of the new error related protocols from Swift -> Objective-C.
Here’s my implementation:
public enum MyError: CustomNSError, Equatable {
case one([String : Any])
case two([String : Any])
case three([String : Any])
/// The domain of the error.
public static var errorDomain: String {
return “MyError"
}
/// The error code within the given domain.
public var errorCode: Int {
switch self {
case .one:
return 50000
case .two:
return 50001
case .three:
return 50002
}
}
/// The user-info dictionary.
public var errorUserInfo: [String : Any] {
var userInfo = [String: Any]()
if case let .one(info) = self {
userInfo = info
} else if case let .two(info) = self {
userInfo = info
} else if case let .three(info) = self {
userInfo = info
}
return userInfo
}
}
Thanks
Ronak
> On Sep 29, 2016, at 5:46 PM, Ronak via swift-users <swift-users at 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.
>
> Thanks for this!
>
>
>> On Sep 29, 2016, at 4:38 PM, Zach Waldowski <zach at waldowski.me <mailto:zach at 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 at swift.org <mailto:swift-users at 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 <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 at swift.org <mailto:swift-users at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-users <https://lists.swift.org/mailman/listinfo/swift-users>
>>
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170302/52ab36c8/attachment.html>
More information about the swift-users
mailing list