[swift-users] Proper Way to make Errors in Swift 3

Ronak ronak2121 at yahoo.com
Mon Mar 6 09:04:23 CST 2017


Hi Ole,

Yes that’s what I’m resorting to now. I had to change my Swift code to return NSError to all clients, regardless of language.

Therefore, I really wonder why CustomNSError even exists. I could have just used NSError from the get go...

Ronak

> On Mar 5, 2017, at 2:20 PM, Ole Begemann <ole at oleb.net> wrote:
> 
> Have you tried explicitly casting the value to NSError when you pass it to Objective-C? I think it should work then.
> 
>    let myError: MyError = ...
>    myObjCFunc(myError as NSError)
> 
> On 02/03/2017 17:29, Ronak via swift-users wrote:
>> 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:
>> 
>> publicenumMyError: CustomNSError, Equatable{
>> 
>>  caseone([String: Any])
>> 
>>  casetwo([String: Any])
>> 
>>  casethree([String: Any])
>> 
>>  /// The domain of the error.
>>  publicstaticvarerrorDomain: String{
>>    return“MyError"
>>  }
>> 
>>  /// The error code within the given domain.
>>  publicvarerrorCode: Int{
>>    switchself{
>>    case.one:
>>      return50000
>>    case.two:
>>      return50001
>>    case.three:
>>      return50002
>>    }
>>  }
>> 
>>  /// The user-info dictionary.
>>  publicvarerrorUserInfo: [String: Any] {
>>    varuserInfo = [String: Any]()
>>    ifcaselet.one(info) = self{
>>      userInfo = info
>>    } elseifcaselet.two(info) = self{
>>      userInfo = info
>>    } elseifcaselet.three(info) = self{
>>      userInfo = info
>>    }
>> 
>>    returnuserInfo
>>  }
>> }
>> 
>> Thanks
>> 
>> Ronak
>> 
>>> On Sep 29, 2016, at 5:46 PM, Ronak via swift-users
>>> <swift-users at swift.org <mailto:swift-users at swift.org> <mailto:swift-users at swift.org <mailto: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>
>>>> <mailto: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:
>>>> 
>>>> externNSString*constMyErrorDomain NS_REFINED_FOR_SWIFT;
>>>> externNSString*constMyErrorUserInfoStringKey NS_REFINED_FOR_SWIFT;
>>>> 
>>>> typedefNS_ENUM(NSInteger, MyErrorCode) {
>>>>    MyErrorCodeOne,
>>>>    MyErrorCodeTwo,
>>>>    MyErrorCodeThree,
>>>> } NS_REFINED_FOR_SWIFT;
>>>> 
>>>> enumMyError: CustomNSError{
>>>> 
>>>>    caseone(String)
>>>>    casetwo
>>>>    casethree
>>>> 
>>>>    staticvarerrorDomain: String{
>>>>        return__MyErrorDomain
>>>>    }
>>>> 
>>>>    varerrorCode: Int{
>>>>        switchself{
>>>>        case.one:
>>>>            return__MyErrorCode.one.rawValue
>>>>        case.two:
>>>>            return__MyErrorCode.two.rawValue
>>>>        case.three:
>>>>            return__MyErrorCode.three.rawValue
>>>>        }
>>>>    }
>>>> 
>>>>    varerrorUserInfo: [String: Any] {
>>>>        varuserInfo = [String: Any]()
>>>>        ifcaselet.one(string) = self{
>>>>            userInfo[__MyErrorUserInfoStringKey] = string
>>>>        }
>>>>        returnuserInfo
>>>>    }
>>>> 
>>>> }
>>>> 
>>>>> On Sep 29, 2016, at 1:17 PM, Ronak via swift-users
>>>>> <swift-users at swift.org <mailto:swift-users at swift.org> <mailto: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
>>>>> @objcpublicclassFoundationError: NSObject, CustomNSError{
>>>>> 
>>>>>    /// The underlying error code
>>>>>    privateletcode: FoundationError.Code
>>>>> 
>>>>>    /// The type of an error code.
>>>>>    @objcpublicenumCode: Int{
>>>>> 
>>>>>        /// An ARCOperationCondition failed during evaluation
>>>>>        caseoperationConditionFailed = 10000
>>>>> 
>>>>>        /// An ARCOperation failed during execution
>>>>>        caseoperationExecutionFailed = 10001
>>>>>    }
>>>>> 
>>>>>    /// The domain of the error.
>>>>>    publicstaticvarerrorDomain: String{
>>>>>        return"FoundationError"
>>>>>    }
>>>>> 
>>>>>    /// The error code within the given domain.
>>>>>    publicvarerrorCode: Int{
>>>>>        returncode.rawValue
>>>>>    }
>>>>> 
>>>>>    /// The user-info dictionary.
>>>>>    publicleterrorUserInfo: [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
>>>>>    publicconvenienceinit(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
>>>>>    publicinit(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
>>>>>    publicoverridefuncisEqual(_object: Any?) -> Bool{
>>>>>        guardletobject = object as? FoundationErrorelse{ returnfalse}
>>>>> 
>>>>>        returnerrorCode == 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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170306/e7984659/attachment.html>


More information about the swift-users mailing list