Swift Mapping for Classes

On this page:

Basic Swift Mapping for Classes

A Slice class is mapped to an open Swift class with the same name. The generated class contains a public stored property for each Slice data member (just as for structures and exceptions). Consider the following class definition:

Slice
class TimeOfDay
{
    short hour;         // 0 - 23
    short minute;       // 0 - 59
    short second;       // 0 - 59
    string tz;          // e.g. GMT, PST, EDT...
}

The Slice compiler generates the following code for this definition:

Swift
open class TimeOfDay: Ice.Value {
    public var hour: Int16 = 0
    public var minute: Int16 = 0
    public var second: Int16 = 0
    public var tz: String = ""

    public required init() {}

    public init(hour: Int16, minute: Int16, second: Int16, tz: String) {
        self.hour = hour
        self.minute = minute
        self.second = second
        self.tz = tz
    }

    open override func ice_id() -> Swift.String {
        return TimeOfDayTraits.staticId
    }

    override open class func ice_staticId() -> String {
        return TimeOfDayTraits.staticId	
    }
}

There are a several things to note about the generated code:

  1. The generated class TimeOfDay inherits from class Ice.Value.  Value is the ultimate ancestor of all classes.
  2. The generated class contains a public stored property for each Slice data member.
  3. The generated class provides a default constructor and a memberwise constructor.

There is quite a bit to discuss here, so we will look at each item in turn.

Inheritance from Value in Swift

Slice classes implicitly inherit from a common base class, Value, which is mapped to the Swift class Ice.ValueValue is a very simple base class with just a few methods:

Swift
open class Value {
    public required init() {}

    open func ice_preMarshal() {}
    open func ice_postUnmarshal() {}

    open func ice_id() -> String {
        return ObjectTraits.staticId
    }

    open class func ice_staticId() -> String {
        return ObjectTraits.staticId
    }

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

The Value methods behave as follows:

  • ice_preMarshal
    The Ice run time invokes this method prior to marshaling the value's state, providing the opportunity for a subclass to validate its declared data members.
  • ice_postUnmarshal
    The Ice run time invokes this method after unmarshaling an value's state. A subclass typically overrides this method when it needs to perform additional initialization using the values of its declared data members.
  • ice_id
    This method returns the run-time type ID for a class instance. If you call ice_id through a reference to a base instance, the returned type id is the actual (possibly more derived) type ID of the instance.
  • ice_staticId
    This method returns the type ID of the corresponding Slice class.
  • ice_getSlicedData
    This functions returns the SlicedData object if the value has been sliced during un-marshaling or nil otherwise.

The type ID for a plain value is ::Ice::Object and not ::Ice::Value, as expected. This is for interoperability with older versions of Ice where Object was used for Value.

Class Data Members in Swift

Data members of Slice classes are mapped exactly as for structures and exceptions: for each data member in the Slice definition, the generated class contains a corresponding public stored property. 

Class Constructors in Swift

A mapped Swift class provides a public default constructor and a public memberwise constructor.

The default constructor initializes all stored properties to zero, nil or empty, as appropriate. You can also declare a default value in your Slice definition to initialize a stored property to a specific value.

Value Factories in Swift

Value factories allow you to create classes derived from the Swift classes generated by the Slice compiler, and tell the Ice run time to create instances of these classes when unmarshaling. For example, with the following simple interface:

Slice
interface Time
{
    TimeOfDay get();
}

The default behavior of the Ice run time will create and return an instance of the generated TimeOfDay class.

If you wish, you can create your own custom derived class, and tell Ice to create and return these instances instead. For example:

Swift
open class CustomTimeOfDay: TimeOfDay {
    public String format() { ... prints formatted data members ... }
}

You then create and register a value factory for your custom class with your Ice communicator:

Swift
let communicator: Communicator = ...


try communicator.getValueFactoryManager().add(factory: { _ in CustomTimeOdDay() }, id: TimeOfData.ice_staticId())

In Swift, derived custom classes are useful if you want to add new stored properties. If you just want to add methods, it is simpler to create an extension for the generated class.

Class Operations in Swift

Operations on classes are deprecated as of Ice 3.7. Skip this section unless you need to communicate with old applications that rely on this feature.

Operations in classes are not mapped at all into the corresponding Swift class. The generated Swift class is the same whether the Slice class has operations or not. 

For a Slice class that defines or inherits operations, the Slice compiler generates instead a separate <class-name>Operations class that can be used to implement an Ice object with these operations. Let's change our example to add a class operation:

Slice
class FormattedTimeOfDay
{
    short hour;         // 0 - 23
    short minute;       // 0 - 59
    short second;       // 0 - 59
    string tz;          // e.g. GMT, PST, EDT...
    string format();
}

The Slice compiler generates the following code:

Swift
open class TimeOfDay: Ice.Value {
    // ... operation format() not mapped at all here
}

// Operations class for servant implementation
public protocol FormattedTimeOfDayOperations {
    func format(current: Ice.Current) throws -> String
}

This Operations class is the skeleton class for this Slice class. Skeleton classes are described in the Server-Side Swift Mapping for Interfaces.

See Also