Creating an XPC Service in Swift
source link: https://matthewminer.com/2018/08/25/creating-an-xpc-service-in-swift
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Matthew Miner
Creating an XPC Service in Swift
August 25, 2018Say you want to add an XPC Service to your Swift app. Fine idea, but notice that Xcode spits out Objective-C when you add an XPC Service target.1 Nobody has time for that. Fortunately converting Xcode’s starter code to Swift is mostly straightforward. Let’s twiddle some knobs and twist a few dials and get you rolling.
After creating an XPC Service target, here named “MyService”, we have four files: main.m, MyService.h, MyService.m, and MyServiceProtocol.h. Rename these to main.swift, MyService.swift, MyServiceDelegate.swift, and MyServiceProtocol.swift. Next, add them to the target’s “Compile Sources” build phase.
Now replace the Objective-C code in each file with its Swift translation.
// main.swift
import Foundation
let delegate = MyServiceDelegate()
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()
// MyService.swift
import Foundation
class MyService: NSObject, MyServiceProtocol {
func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void) {
let response = string.uppercased()
reply(response)
}
}
// MyServiceDelegate.swift
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
}
}
// MyServiceProtocol.swift
import Foundation
@objc public protocol MyServiceProtocol {
func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void)
}
Before compiling this code we need to tweak build settings:
- Install Objective-C Compatibility Header: NO
- Objective-C Generated Interface Header Name: “”
- Runtime Search Paths: @loader_path/../../../../Frameworks
- Swift Language Version: whatever version of Swift you use
With any luck we can now build. In our main application we delegate a task to our service by creating an NSXPCConnection
with the name of the target’s bundle identifier then calling the functions defined in MyService
.
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)
}
That’s it! For reference you can find the above code snippets in this Gist. Boy howdy.
Thanks to GitHub user adur1990 for Swift 4 compatibility fixes.
As of Xcode 9, at least. I hope Apple changes this in future versions and this bone dry article can be tossed into the World Wide Web’s trash bin. ↩
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK