[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