Skip to content

Instantly share code, notes, and snippets.

@mminer
Last active August 6, 2022 05:33
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mminer/be55bcdf7c4ff004ecafba6a664addc5 to your computer and use it in GitHub Desktop.
Save mminer/be55bcdf7c4ff004ecafba6a664addc5 to your computer and use it in GitHub Desktop.
Components of XPC service.
import Foundation
let delegate = MyServiceDelegate()
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()
import Foundation
class MyService: NSObject, MyServiceProtocol {
func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void) {
let response = string.uppercased()
reply(response)
}
}
import Foundation
class MyServiceDelegate: NSObject, NSXPCListenerDelegate {
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
let exportedObject = MyService()
newConnection.exportedInterface = NSXPCInterface(with: MyServiceProtocol.self)
newConnection.exportedObject = exportedObject
newConnection.resume()
return true
}
}
import Foundation
@objc public protocol MyServiceProtocol {
func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void)
}
import MyService
...
let connection = NSXPCConnection(serviceName: "com.matthewminer.MyService")
connection.remoteObjectInterface = NSXPCInterface(with: MyServiceProtocol.self)
connection.resume()
let service = connection.remoteObjectProxyWithErrorHandler { error in
print("Received error:", error)
} as? MyServiceProtocol
service?.upperCaseString("Hello XPC") { response in
print("Response from XPC service:", response)
}
@adur1990
Copy link

This is not working with macOS Mojave and Swift 4.2.

The connection to service named com.matthewminer.MyService was invalidated.

Apple's documentation is horrible. I can not figure out how to do this. Any suggestions?

@adur1990
Copy link

So, I figured it our. In Swift 4 you have to pass @escaping to the result parameter of the service:

// MyService.swift

import Foundation

class MyService: NSObject, MyServiceProtocol {
    func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void) {
        let response = string.uppercased()
        reply(response)
    }
}
// MyServiceProtocol.swift

import Foundation

@objc public protocol MyServiceProtocol {
    func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void)
}

@mminer
Copy link
Author

mminer commented Dec 12, 2018

@adur1990: Thanks for the fix, I updated the Gist.

@madscientistjaidev
Copy link

@mminer - listener.resume() in main.swift is throwing the following error. Any idea how to fix it?

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

@mminer
Copy link
Author

mminer commented Jun 26, 2019

@madscientistjaidev: I'm not too sure what might cause that error. I tried the code in the Gist in a fresh project using the Xcode 11 beta + Swift 5 and it worked without a hitch. Sorry I can't be of more help.

@tt-embodied
Copy link

Thanks for making your code available.. I reference this every time I create a xpc service and want swift instead. Maybe Xcode 11 will make this obsolete (we can hope).

@mminer
Copy link
Author

mminer commented Jul 31, 2019

@tt-embodied: Glad it's helpful!

@antelle
Copy link

antelle commented Feb 20, 2020

If anyone like me tried it in a command-line tool and got “The connection to service named ... was invalidated.”, it’s because it doesn’t seem to work in command-line tools at all, the same code in an app will work.

@rsalesas
Copy link

rsalesas commented Mar 10, 2020

I've tried this in a SwiftUI app and I'm getting the error "The connection to service named ... was invalidated". Any ideas?

UPDATE: My problem was that the XPS Service was not copied to Contents/XPCServices. If you don't properly place the XPC Service within the app bundle, this doesn't work (also why you cannot call the XPC Service from a command line that is expecting it in it's bundle - haven't figure out how to do this yet)

@mminer
Copy link
Author

mminer commented Mar 11, 2020

@rsalesas Good to know, that’s an easy mistake to make. Thanks for the extra info.

@ben-z
Copy link

ben-z commented Apr 14, 2020

I also just ran into this error:

Domain=NSCocoaErrorDomain Code=4099 "The connection to service on pid 0 named <service-name> was invalidated."

It turns out I just misspelled the service name when initializing the NSXPCConnection. Hope this saves someone a few hours of debugging lol.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment