The OutputStream Interface in Swift

On this page:

Initializing an OutputStream in Swift

The OutputStream class provides a number of overloaded initializers:

Swift
public class OutputStream {
    public convenience init(communicator: Communicator)
    public init(communicator: Communicator, encoding: EncodingVersion)
}

The initializers accept the following parameters:

  • A communicator instance
  • An encoding version

If you omit an encoding version, the stream uses the default encoding version of the communicator.

Inserting into an OutputStream in Swift

OutputStream provides a number of write methods that allow you to insert Slice types into the stream.

For example, you can insert a boolean and a sequence of strings into a stream as follows:

Swift
let seq = ["Ice", "rocks!"]
let out = Ice.OutputStream(communicator)
out.write(true)
out.write(seq)
let data = out.finished()

Here are the methods for inserting data into a stream:

Swift
public extension OutputStream {
    /// Writes a numeric value to the stream.
    func write<Element>(_ v: Element) where Element: StreamableNumeric
    /// Writes an optional numeric value to the stream.
    func write<Element>(tag: Int32, value: Element?) where Element: StreamableNumeric
    /// Writes a sequence of numeric values to the stream.
    func write<Element>(_ v: [Element]) where Element: StreamableNumeric
    /// Writes an optional sequence of numeric values to the stream.
    func write<Element>(tag: Int32, value: [Element]?) where Element: StreamableNumeric
    /// Writes a byte to the stream.
    func write(_ v: UInt8)
    /// Writes a sequence of bytes to the stream.
    func write(_ v: [UInt8])
    /// Writes a sequence of bytes to the stream.
    func write(_ v: Data)
    /// Writes an optional sequence of bytes to the stream.
    func write(tag: Int32, value: Data?
    /// Writes a boolean value to the stream.
    func write(_ v: Bool)
    /// Writes an optional boolean value to the stream.
    func write(tag: Int32, value: Bool?)
    /// Writes a sequence of boolean values to the stream.
    func write(_ v: [Bool])
    /// Writes an optional sequence of boolean values to the stream.
    func write(tag: Int32, value: [Bool]?)
    /// Writes a size to the stream.
    func write(size: Int32)
    /// Writes a size to the stream.
    func write(size: Int)
    /// Writes an enumerator to the stream.
    func write(enum val: UInt8, maxValue: Int32)
    /// Writes an optional enumerator to the stream.
    func write(tag: Int32, val: UInt8, maxValue: Int32)
    /// Writes an enumerator to the stream.
    func write(enum val: Int32, maxValue: Int32)
    /// Writes an optional enumerator to the stream.
    func write(tag: Int32, val: Int32, maxValue: Int32)
    /// Writes a string to the stream.
    func write(_ v: String)
    /// Writes a string to the stream.
    func write(tag: Int32, value v: String?)
    /// Writes a sequence of strings to the stream.
    func write(_ v: [String])
    /// Writes an optional sequence of strings to the stream.
    func write(tag: Int32, value v: [String]?)
    /// Writes a proxy to the stream.
    func write(_ v: ObjectPrx?)
    /// Writes an optional proxy to the stream.
    func write(tag: Int32, value v: ObjectPrx?)
    /// Writes a value to the stream.
    func write(_ v: Value?)
    /// Writes an optional value to the stream.
    func write(tag: Int32, value v: Value?)
    /// Writes a user exception to the stream.
    func write(_ v: UserException)
    func writeOptional(tag: Int32, format: OptionalFormat) -> Bool
    func writeOptionalVSize(tag: Int32, len: Int, elemSize: Int) -> Bool
    /// Writes bytes to the stream.
    func write(raw: Data)
}

The write method has overloads for inserting all the primitive types, as well as sequences of primitive types. The Slice to Swift compiler generates additional overloads for user-defined types. The remaining methods have the following semantics:

  • func startValue(data: SlicedData?)
    func endValue()
    When marshaling the slices of a class instance, the application must first call startValue, then marshal the slices, and finally call endValue. The caller can pass a SlicedData object containing the preserved slices of unknown more-derived types, or null if there are no preserved slices.

  • func startException(data: SlicedData?)
    func endException()
    When marshaling the slices of an exception, the application must first call startException, then marshal the slices, and finally call endException. The caller can pass a SlicedData object containing the preserved slices of unknown more-derived types, or 0 if there are no preserved slices.
  • func startSlice(typeId: String, compactId: Int32, last: Bool)
    func endSlice()
    Starts and ends a slice of class or exception. The call to startSlice must include the type ID for the current slice, the corresponding compact ID for the type (if any), and a boolean indicating whether this is the last slice of the class instance or exception. The compact ID is only relevant for class instances; pass a negative value to indicate the encoding should use the string type ID.
  • func startEncapsulation(encoding: EncodingVersion, format: FormatType)
    func startEncapsulation()
    func endEncapsulation()
    Starts and ends an encapsulation, respectively. The first overloading of startEncapsulation allows you to specify the encoding version as well as the format to use for any class instances and exceptions marshaled within this encapsulation.
  • func writeEmptyEncapsulation(_ encoding: EncodingVersion
    Writes an encapsulation having the given encoding version with no encoded data.
  • func writeEncapsulation(_ v: Foundation.Data)
    Copies the data representing an encapsulation from the given Foundation.Data object into the stream.
  • currentEncoding: EncodingVersion { get ... } 
    Returns the encoding version currently being used by the stream.
  • func writePendingValues()
    Encodes the state of class instances whose insertion was delayed during write. With encoding version 1.0, this method must only be called exactly once when non-optional data members or parameters use class types. This method is no-op with encoding version 1.1.
  • func writeOptional(tag: Int32, format: OptionalFormat) -> Bool
    Prepares the stream to write an optional value with the given tag and format. Returns true if the value should be written, or false otherwise. A return value of false indicates that the encoding version in use by the stream does not support optional values. If this method returns true, the data associated with that optional value must be written next. Optional values must be written in order by tag from least to greatest. The OptionalFormat enumeration is defined as follows:

    Swift
    enum OptionalFormat: UInt8 {
        case F1 = 0
        case F2 = 1
        case F4 = 2
        case F8 = 3
        case Size = 4
        case VSize = 5
        case FSize = 6
        case Class = 7
    }

    Refer to the encoding discussion for more information on the meaning of these values.

  • func startSize() -> Int32
    func endSize(position: Int32)
    The encoding for optional values uses a 32-bit integer to hold the size of variable-length types. Calling startSize writes a placeholder value for the size and returns the starting position of the size value; after writing the data, call endSize to patch the placeholder with the actual size at the given position.
  • func finished() -> Foundation.Data 
    Indicates that marshaling is complete and returns the encoded data. This method must only be called once.

OutputStream Extensions

The OutputStream class provides all of the low-level methods necessary for encoding Ice types. However, it would be tedious and error-prone to manually encode complex Ice-types such as classes, structures, and enumerated types. the Slice compiler generates extensions to the OutputStream for encoding complex Ice types.

We will use the following Slice definitions to demonstrate the language mapping:

Slice
module M
{
    struct S
    {
        ...
    }
    enum E { ... }
    class C
    {
        ...
    }
    interface I
    {
        ...
    }
}

The Slice compiler generates the corresponding OutputStream extension shown below:

Swift
/// An Ice.OutputStream extension to write S structured values from the stream.
public extension Ice.OutputStream {
    /// Write a S structured value to the stream.
    func write(_ v: S) { ... }
    /// Write an optional S? structured value to the stream.
    func write(tag: Swift.Int32, value: S?) { ... }
}


/// An Ice.OutputStream extension to write E enumerated values to the stream.
public extension Ice.OutputStream {
    /// Writes an enumerated value to the stream.
    func write(_ v: E) { ... }
    /// Writes an optional enumerated value to the stream.
    func write(tag: Swift.Int32, value: E?) { ... }
}

No additional code is generated for marshaling instances of class types, such as type C that we defined above. Applications should use OutputStream.write to insert class instances.


See Also