[swift-users] Proper Way to make Errors in Swift 3
Ronak
ronak2121 at yahoo.com
Thu Sep 29 16:46:22 CDT 2016
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> 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>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160929/ea837bf4/attachment.html>
More information about the swift-users
mailing list