Swift Mapping for Exceptions

On this page:

Base Protocol for Ice Exceptions

All exceptions thrown by Ice adopt the protocol Ice.Exception:

Swift
public protocol Exception: Error {
    func ice_id() -> String
    class func ice_staticId() -> String
}

Swift Mapping for User Exceptions

Here is a fragment of the Slice definition for our world time server once more:

Slice
exception GenericError
{
    string reason;
}
exception BadTimeVal extends GenericError {}

These exception definitions map as follows:

Swift
open class GenericError: Ice.UserException {
    public var reason: String = ""

    required init() {}

    public init(reason: String) {
        self.reason = reason
    }

    open override func ice_id() -> String {
        return "::M::GenericError"
    }

    open override class func ice_staticId() -> String {
        return "::M::GenericError"
    }
}

open class BadTimeVal: GenericError {
    open override func ice_id() -> String {
        return "::M::BadTimeVal"
    }

    open override class func ice_staticId() -> String {
        return "::M::BadTimeVal"
    }
}

Each Slice exception is mapped to a Swift class with the same name. For each exception member, the corresponding class contains a public stored property. (Since BadTimeVal does not have members, the generated classes for these exceptions also do not have members.)

The inheritance structure of the Slice exceptions is preserved for the generated classes, so BadTimeVal inherits from GenericError.

Each exception has a default initializer and a memberwise initializer marked public. You can declare default values for your exception data members just like for members of Slice structures.

All Ice exceptions provide an ice_id instance method and an ice_staticId type method that return the type-id of the exception. For example BadTimeVal.ice_staticId() returns "::M::BadTimeVal".

All user exceptions ultimately inherit from Ice.UserException. In turn, Ice.UserException adopts Ice.Exception:

Swift
open class UserException: Exception {
    required init() {}

    open func ice_id() -> String {
        return "::Ice::UserException"
    }

    open class func ice_staticId() -> String {
        return "::Ice::UserException"
    }

    open func ice_getSlicedData() -> SlicedData? {
        return nil
    }
}


Swift Mapping for Run-Time Exceptions

The Ice run time throws run-time exceptions for a number of pre-defined error conditions. All run-time exceptions directly or indirectly derive from from class Ice.LocalException (which, in turn, adopts Ice.Exception):

Swift
open class LocalException: Exception {
    public let file: String
    public let line: Int

    public init(file: String = #file, line: Int = #line) {
        self.file = file
        self.line = line
    }

    open func ice_id() -> String {
        return "::Ice::LocalException"
    }

    open class func ice_staticId() -> String {
        return "::Ice::LocalException"
    }
}


Recall the inheritance diagram for user and run-time exceptions. By catching exceptions at the appropriate point in the hierarchy, you can handle exceptions according to the category of error they indicate:

  • protocol Ice.Exception
    This is the root of the complete inheritance tree. Catching Ice.Exception catches both user and run-time exceptions. 

  • class Ice.UserException
    This is the root exception for all user exceptions. Catching Ice.UserException catches all user exceptions (but not run-time exceptions).
  • class Ice.LocalException
    This is the root exception for all run-time exceptions. Catching Ice.LocalException catches all run-time exceptions (but not user exceptions).
  • class Ice.TimeoutException
    This is the base exception for both operation-invocation and connection-establishment timeouts.
  • class Ice.ConnectTimeoutException
    This exception is raised when the initial attempt to establish a connection to a server times out.

For example, a ConnectTimeoutException can be handled as ConnectTimeoutExceptionTimeoutExceptionLocalException, or Exception.

You will probably have little need to catch run-time exceptions as their most-derived type and instead catch them as LocalException; the fine-grained error handling offered by the remainder of the hierarchy is of interest mainly in the implementation of the Ice run time. Exceptions to this rule are the exceptions related to facet and object life cycles, which you may want to catch explicitly. These exceptions are FacetNotExistException and ObjectNotExistException, respectively.

See Also