Skip to main content
Skip table of contents

Client-Side Swift Mapping for Interfaces

Proxy Protocols

On the client side, a Slice interface maps to an empty Swift protocol. A public extension of this protocol provides two methods for each Slice operation of your Slice interface.

Consider the following Slice interface:

SLICE
module M
{
    interface Simple
    {
        void op();
    }
}

The Slice compiler generates the following definitions for use by the client:

SWIFT
// in module M

public protocol SimplePrx: Ice.ObjectPrx {}

public extension SimplePrx {
    func op(context: Ice.Context? = nil) async throws {
        ...
    }
}

As you can see, the compiler generates a proxy protocol SimplePrx. In general, the generated name is <interface-name>Prx.

In the client's address space, an instance of SimplePrx is the local ambassador for a remote instance of an Ice object that implements Simple and is known as a proxy instance. All the details about the server-side object, such as its address, what protocol to use, and its object identity are encapsulated in that instance.

Creating a Proxy

For each proxy, the Slice compiler generate amakeProxy factory function in the same Swift module. With our previous example:

SWIFT
public protocol SimplePrx: Ice.ObjectPrx {}

public func makeProxy(communicator: Ice.Communicator, 
                      proxyString: String, 
                      type: SimplePrx.Protocol) throws -> SimplePrx {
    ...
}

Call makeProxy to create a proxy from a communicator and a “stringified” proxy:

SWIFT
let simple = try makeProxy(
    communicator: communicator, proxyString: "simple:tcp -h localhost -p 4061",
    type: SimplePrx.self)

Inheritance from Ice.ObjectPrx

All generated proxy protocols inherit directly or indirectly from the Ice.ObjectPrx protocol, reflecting the fact that all Slice interfaces implicitly inherit from Object.

Interface Inheritance

Inheritance relationships among Slice interfaces are maintained in the generated Swift protocols. For example:

SLICE
module M
{
    interface A { ... }
    interface B { ... }
    interface C extends A, B { ... }
}

The generated code for CPrx reflects the inheritance hierarchy:

SWIFT
public protocol CPrx: APrx, BPrx {}

Given a proxy for C, a client can invoke any operation defined for interface C, as well as any operation inherited from C's base interfaces.

Casting Proxy

For each proxy, the Slice compiler generate 2 helper functions that allow you to convert any proxy into a proxy of this type. With our Simple example:

SWIFT
public protocol SimplePrx: Ice.ObjectPrx {}

public func uncheckedCast(prx: Ice.ObjectPrx, 
                          type: SimplePrx.Protocol, 
                          facet: String? = nil) -> SimplePrx {
    ...
}

public func checkedCast(prx: Ice.ObjectPrx, 
                        type: SimplePrx.Protocol, 
                        facet: String? = nil,
                        context: Ice.Context? = nil) async throws -> SimplePrx? {
    ...
}

uncheckedCast

The uncheckedCast function allows you to convert a proxy into another proxy. For example:

C#
// Convert a SimplePrx into a WidgetPrx, even though the two types are unrelated.
let widget = uncheckedCast(prx: simple, type: WidgetPrx.self)

uncheckedCast is a local operation that always succeeds.

checkedCast

checkedCastis a conditional cast of the proxy: this function makes a remote call to the target object to check if this object implements the proxy’s Slice interface. For example:

C#
// Call operation ice_isA on the Ice object to check if it implements Slice interface
// Widget.
let widget = await checkedCast(prx: simple, type: WidgetPrx.self)

If the target object implements the Slice interface, checkedCastreturns a non-nil proxy, just like uncheckedCast. If the target object doesn’t implement this interface, checkedCast returns nil. checkedCastcan also throw an exception, for example if it cannot reach the remote object.

While checkedCast sounds safer than uncheckedCast (you’re making an additional check before casting), in practice you know or should know the type of your proxies and calling checkedCast is rarely necessary.

Proxy Factory Methods

The base proxy interface ObjectPrx supports a variety of methods for customizing a proxy. Since proxies are immutable, each of these factory methods returns a copy of the original proxy that contains the desired modification. For example, you can obtain a proxy configured with a ten second invocation timeout as shown below:

SWIFT
var greeter = try makeProxy(communicator: ..., type: GreeterPrx.self)

// Create a new GreeterPrx and assign it to greeter.
greeter = greeter.ice_invocationTimeout(10000)

The factory methods usually return a proxy of the same type as the current proxy, as in the example above.

The only exceptions are the factory methods ice_facet and ice_identity. Calls to either of these methods may produce a proxy for an object of an unrelated type, and you need to cast the returned proxy. For example:

SWIFT
let greeter = try makeProxy(communicator: ..., type: GreeterPrx.self)
let greeterAdmin = uncheckedCast(
    prx: greeter.ice_facet("admin"), type: GreeterPrx.self)
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.