Check whether XPC remote proxy responds to selector, without causing exception and connection invalidation?

I have several processes maintaining NSXPConnection to an XPC service. The connections are bi-directional. Each side service and clients) of the connection exports an object, and an XPCInterface. The @protocols are different - to the service, and from the service to clients.

So long as all the "clients" fully implement their "call-back" @protocol, there's no problem. All works fine.

However - If a client does NOT implement a method in the "call back protocol", or completely neglects to export an object, or interface - and the service attempts to call back using the nonexistent method -- the XPC connection invalidates immediately.

So far - expected behaviour.

However, if I want the service to behave to the client a little like a "delegate" style -- and check first whether the client "respondsToSelector" or even - supports an interface BEFORE calling it, then this doesn't work.

When my XPC service tries the following on a client connection:

if (xpcConnection.remoteObjectInterface == nil)
    os_log_error(myXPCLog, "client has no remote interface);

the condition is never met - i.e. the "remoteObjectInterface is never nil even when the client does NOT configure its NSXPCConnection with any incoming NSXPCInterface, and does not set an "exportedObject"

Furthermore, the next check:

  if ([proxy respondsToSelector:@selector(downloadFiltersForCustomer:withReply:)]) {
}

will not only fail - but will drop the connection. The client side gets the invalidation with the following error:

<NSXPCConnection: 0x600000b20000> connection to service with pid 2477 named com.proofpoint.ecd: received an undecodable message for proxy 1 (no exported object to receive message). Dropping message.

I guess the "undecidable message" is the respondsToSelector - because the code doesn't get to attempt anything else afterwards, the connection drops.

Is there a way to do this check "quietly", or suffering only "interruption", but without losing the connection,

Answered by DTS Engineer in 821961022
However, if I want the service to behave to the client a little like a "delegate" style

Yeah, that’s not a pattern that’s well-supported by XPC.

I put this in the ‘XPC is not DO’ bucket [1]. The goal of DO was to hide the IPC as much as possible. That’s not a goal of XPC [2]. When you’re working with an XPC object you know you’re doing IPC and are expected to code accordingly. Thus, there’s no reason for forward -respondsToSelector: and other low-level Objective-C runtime stuff.

You can try to make up for this yourself but my advice is that you not use this pattern.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] And thank goodness for that! (-:

[2] Ditto.

Accepted Answer
However, if I want the service to behave to the client a little like a "delegate" style

Yeah, that’s not a pattern that’s well-supported by XPC.

I put this in the ‘XPC is not DO’ bucket [1]. The goal of DO was to hide the IPC as much as possible. That’s not a goal of XPC [2]. When you’re working with an XPC object you know you’re doing IPC and are expected to code accordingly. Thus, there’s no reason for forward -respondsToSelector: and other low-level Objective-C runtime stuff.

You can try to make up for this yourself but my advice is that you not use this pattern.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] And thank goodness for that! (-:

[2] Ditto.

(Blushing) what does 'DO' stand for?

And what architectural recommendation would you give for making XPC client / service implementation be a bit more "flexible" and not fail with exceptions and crashes just because a client did not implement the whole @protocol ?

I found out the hard way - (and not without your kind help) along the last 3 years that NSXPC is implemented in quite limited way, and not everything you expect from Obj-C messaging works as expected --

  1. only one "reply block"
  2. "reply block" must be last argument.
  3. "reply block can only be called once
  4. not any class can participate in the @protocol supported by an NSXPCInterface, and you must manually add classes you need.
  5. Now this... "respondsToSelector:" drops the XPC connection when something isn't implemented

etc.

I wish at the very least the NSXPCConnection documentation would cover these limitations as requirements, so I wouldn't have to apply "normal MacOS thinking" again and again, just to reach the end of implementation and stumble on the limitations like this.

It is both frustrating, and pushes into bad design. I would design very differently had I known these things BEFORE I started implementing.

Check whether XPC remote proxy responds to selector, without causing exception and connection invalidation?
 
 
Q