Just to be clear, your XPC process will quit when the parent app quits. At least, mine does. Your question is: How to kill it before then?
That is simple: Just call exit(0)
in your XPC process immediately after it invokes the completion handler which sends the output back to the parent app. I needed to do this in a project last month, because the XPC process was using an Apple private framework, and exitting it was the only way I could figure to stop a certain undesired and inexplicable (since I have no documentation on the private framework) side effect.
Upon exitting this XPC process, however, I found that, oddly, it continued to run for some milliseconds, and if my parent app opened another connection to this same XPC service in the meantime, the doomed XPC process will accept the new connection just prior to killing itself, leaving the parent app hanging. I've actually seen this happen several times.
So, a follow-up question is: Should you kill it just because you want to be nice? I think the answer is no, according to the following quote from Apple's Daemons and Services Programming Guide > Creating XPC Services
XPC services are managed by launchd, which launches them on demand,
restarts them if they crash, and terminates them (by sending SIGKILL)
when they are idle.
To summarize: Just invalidate your connections when done, and let launchd worry about killing. Also, don't hold your breath. I've had my app running for the past two hours, and the XPC process, last connection closed two hours ago, is still running.