People starting to learn Cocoa program often ask why Apple picked a weird, obscure, language like Objective-C instead of their favorite language. In fact, Apple inherited the choice of language from NeXT, but the question still stands. One of the answers lies in the distributed objects system.
NeXT introduced distributed objects in the early '90s. The system takes advantage of a few features of Objective-C to work entirely transparently. In the NeXT days, Portable Distributed Objects interacted with a lot of foreign object models — one version wrapped OLE (later COM, later ActiveX) objects — but the Apple version only works on OS X.
How it Works
The core flow control primitive in an object oriented language like Objective-C is the message. Objects communicate by exchanging messages. This is implemented in Objective-C by the runtime library. When you send a message, the runtime library looks up the method that should be called to handle it. The clever bit happens when there is no such method.
Newer Objective-C runtimes have a number of fall-back mechanisms for this case, but the traditional one in Cocoa is to call two methods in the receiver. The first is -methodSignatureForSelector:. This returns an object encapsulating metadata about the nonexistent method. This is then used to deconstruct the stack frame and create an NSInvocation object encapsulating the message. This is then delivered to the -forwardInvocation: method in the object.
The -forwardInvocation: implementation in NSObject is pretty boring. It just throws an exception saying that the object doesn't respond to that message. The distributed object system adds an NSProxy subclass, NSDistantObject, that is a bit more clever. Messages sent to this are serialized and sent over an NSConnection instance.
When you pass primitive types, like ints or NSRects as arguments, they are copied. When you pass objects, one of two things happens. They might be copied, by sending them an -encodeWithCoder: message and sending the encoded version. Alternatively, they are passed by reference. A new NSDistantObject instance is created at the far end of the connection and messages sent to it are passed back by the same mechanism.
Note that you always use the same class, NSDistantObject, for all objects. You aren't required to generate new stub classes for each one, as you are with some remote object systems.