Distributed Objects
Here's how the Distributed Objects are structured internally:
-
NSPortis a type that abstracts away a port -- something that can receive and send messages (NSPortMessage). The few commonly used concrete port classes areNSMachPort(Mach port),NSSocketPort(network socket, possibly talking to another host), andNSMessagePort(another wrapper over Mach ports). With some luck, it's possible to use a custom port class, too.NSPortis really supposed to be a Mach port (and that's what[NSPort port]creates), while other port types have kind of been retrofitted on top of the existing Mach port semantics.NSPortitself conforms toNSCoding, so you can "send" a port over another port (it does not support coders other thanNSPortCoder).Some
NSPortsubclasses may not fully work unless you're using them for Distributed Objects (with an actualNSConnection *). -
NSPortMessageroughly describes a Mach message. It has "send" and "receive" ports, a msgid, and an array of components. Individual components can be either data (NSData) or a port (NSPort), corresponding toMACH_MSG_OOL_DESCRIPTORandMACH_MSG_PORT_DESCRIPTOR. Passing a port will only work with ports of the same type as the port you're sending this message through. -
NSPortNameServerabstracts away a name server that you can use to map (string) names to port. You can register your port for a name and lookup other ports by name.NSMachBootstrapServerimplements this interface on top of the Mach bootstrap server (launchd on Darwin). -
NSPortCoderis anNSCoderthat essentially serializes and deserializes data (and ports) to and from port messages, using the sameNSCodinginfrastructure a lot of types already implement. Unlike other coders (read: archivers), it supports encoding and decoding ports, though this is mostly useless as DO itself make very little use of this.NSPortCoderitself is an abstract class. In older versions of OS X, it had a concrete subclass,NSConcretePortCoder, which only supported non-keyed (also called unkeyed) coding. In newer versions,NSConcretePortCoderitself is now an abstract class, and it has two subclasses,NSKeyedPortCoderandNSUnkeyedPortCoder.NSPortCodersubclasses send thereplacementObjectForPortCoder:message to the objects they encode. The default implementation of that method replaces the object with aNSDistantObject(a Distributed Objects proxy), no matter whether the type conforms toNSCodingor not. Some DO-aware classes that wish to be encoded differently (for example,NSString) override that method, and usually do something like this:- (id) replacementObjectForPortCoder: (NSPortCoder *) portCoder { if ([portCoder isByref]) { return [super replacementObjectForPortCoder: portCoder]; } return self; } -
NSDistantObjectis a proxy (NSProxy) that stands in for a remote object and forwards any messages over to the remote object. The sameNSDistantObjecttype is returned by the defaultNSObjectimplementation ofreplacementObjectForPortCoder:, and this instance is what gets serialized and sent over the connection (and deserialized to aNSDistantObjecton the other end). -
NSConnectionrepresents a connection (described by a pair of ports).NSConnectionstores local and remote object maps, to intern created proxies (NSDistantObjects) when receiving or sending objects.NSConnectionactually implements forwarding method invocations, and also serves as a port's delegate, handling received messages.
You would think that NSPort, NSPortMessage, NSPortNameServer, and
NSPortCoder do not "know" they're being used for DO/RPC, and are generic
enough to be used for regular communication directly. This is almost true, but
DO specifics pop up in unexpected places.
Resources
- https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/DistrObjects/DistrObjects.html
- GNUstep implementation