In doing some work, I realized I didn't understand XPC (or at least, the higher-level APIs) at all. So I did what I usually try to do, which is to write a completely, brain-dead simple program to use it, and then keep expanding until I understand it. This also, to my utmost embarrassment, will make it transparently clear how ignorant I am. (Note that, for this, I am not using Xcode -- just using swiftc
to compile, and then manually run.)
I started with this, to be the server side:
import Foundation
class ConnectionHandler: NSObject, NSXPCListenerDelegate {
override init() {
super.init()
print("ConnectionHandler.init()")
}
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
print("ConnectionHandler.listener()")
return false
}
}
let handler = ConnectionHandler()
let listener = NSXPCListener(machServiceName: "com.kithrup.test")
listener.delegate = handler
listener.resume()
print("listener = \(listener)")
dispatchMain()
That ... does absolutely nothing, of course, but runs, and then I tried to write the client side:
import Foundation
@objc protocol Hello {
func hello()
}
class HelloClass: NSObject, Hello {
override init() {
super.init()
}
func hello() {
print("In HelloClass.hello()")
}
}
let hello = HelloClass()
let connection = NSXPCConnection(machServiceName: "com.kithrup.test", options: [])
connection.exportedInterface = NSXPCInterface(with: Hello.self)
let proxy = connection.remoteObjectProxyWithErrorHandler({ error in
print("Got error \(error)")
}) as? Hello
print("proxy = \(proxy)")
connection.resume()
dispatchMain()
That gets proxy
as nil
. Because it can't coerce it to something of Hello
protocol. And at no point, do I get the message from the server-side listener.
So clearly I am doing everything wrong. Can anyone offer some hints?
XPC does not support communication between arbitrary processes. For a client to connect to a listener the listener must be managed by launchd
, including:
-
A
launchd
daemon or agent -
An XPC Service
-
A Service Management login item
If you plan to ship a product then you must design it around this constraint. However, if you just want to noodle around with XPC then there’s a really good way to do this within a single process, namely an anonymous listener (+[NSXPCListenerEndpoint anonymousListener]
). While this is intended to be used as part of more complex XPC strategies, you can use it as a simple loopback mechanisms, allowing you to have both the client and listener running in the same process.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"