The server-side mapping for interfaces provides an up-call API for the Ice run time: by implementing methods in a servant class, you provide the hook that gets the thread of control from the Ice server-side run time into your application code.
On this page:
Skeleton Classes in Objective-C
On the client side, interfaces map to proxy protocols and classes. On the server side, interfaces map to skeleton protocols and classes. A skeleton is a class that has a method for each operation on the corresponding interface. For example, consider our Slice definition for the
The Slice compiler generates the following definition for this interface:
As you can see, the server-side API consists of a protocol and a class, known as the skeleton protocol and skeleton class. The methods of the skeleton class are internal to the mapping, so they do not concern us here. The skeleton protocol defines one method for each Slice operation. As for the client-side mapping, the method name is the same as the name of the corresponding Slice operation. If the Slice operation has parameters or a return value, these are reflected in the generated method, just as they are for the client-side mapping. In addition, each method has an additional trailing parameter of type
ICECurrent. This parameter provides additional information about an invocation to your server-side code.
As for the client-side mapping, the generated code reflects the fact that all Slice interfaces and classes ultimately derive from
Ice::Object. As you can see, the generated protocol incorporates the
ICEObject protocol, and the generated class derives from the
Servant Classes in Objective-C
The Objective-C mapping supports two different ways to implement servants. You can implement a servant by deriving from the skeleton class and implementing the methods for the Slice operations in your derived class. Alternatively, you can use a delegate servant, which need not derive from the skeleton class.
Derived Servants in Objective-C
To provide an implementation for an Ice object, you can create a servant class that derives from the corresponding skeleton class. For example, to create a servant for the
Node interface, you could write:
By convention, servant classes have the name of their interface with an
I-suffix, so the servant class for the
Node interface is called
NodeI. (This is a convention only: as far as the Ice run time is concerned, you can choose any name you prefer for your servant classes.)
NodeI derives from
FSNode, that is, it derives from its skeleton class. In addition, it adopts the
FSNode protocol. Adopting the protocol is not strictly necessary; however, if you do write your servants this way, the compiler emits a warning if you forget to implement one or more Slice operations for the corresponding interface, so we suggest that you make it a habit to always have your servant class adopt its skeleton protocol.
As far as Ice is concerned, the
NodeI class must implement the single
name method that is defined by its skeleton protocol. That way, the Ice run time gets a servant that can respond to the operation that is defined by its Slice interface. You can add other methods and instance variables as you see fit to support your implementation. For example, in the preceding definition, we added a
myName instance variable and property and a convenience constructor. Not surprisingly, the convenience constructor initializes the
myName instance variable and the
name method returns the value of that variable:
Delegate Servants in Objective-C
An alternate way to implement a servant is to use a delegate.
ICEServant provides two constructors to do this:
delegate parameter specifies an object to which the servant will delegate operation invocations. That object need not derive from the skeleton class; the only requirement on the delegate is that it must have an implementation of the methods corresponding to the Slice operations that are called by clients. As for derived servants, we suggest that the delegate adopt the skeleton protocol, so the compiler will emit a warning if you forget to implement one or more Slice operations in the delegate.
The implementation of the Slice operations in a delegate servant is exactly the same as for a derived servant.
Delegate servants are useful if you need to derive your servant implementation from a base class in order to access some functionality. In that case, you cannot also derive the servant from the generated skeleton class. A delegate servant gets around Objective-C's single inheritance limitation and saves you having to write a servant class that forwards each operation invocation to the delegate.
Another use case are different interfaces that share their implementation. As an example, consider the following Slice definitions:
op2 are substantially similar in their implementation and share common state, it can be convenient to implement the servants for
Intf2 using a common delegate class:
See Instantiating an Objective-C Servant for an example of how to instantiate delegate servants.
Delegate servants do not permit you to override operations that are inherited from
ICEObject (such as
ice_ping). Therefore, if you want to override
ice_ping, for example, to implement a default servant, you must use a derived servant.
The Ice run time creates an
NSAutoReleasePool object before dispatching server-side invocations. The pool is released once the dispatch is complete.