Inter-process communication

RSS for tag

Share data through Handoff, support universal links to your app's content, and display activity-based services to the user using inter-process communication.

Posts under Inter-process communication tag

19 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Can child processes inherit Info.plist properties of a parent app (such as LSSupportsGameMode)?
My high-level goal is to add support for Game Mode in a Java game, which launches via a macOS "launcher" app that runs the actual java game as a separate process (e.g. using the java command line tool). I asked this over in the Graphics & Games section and was told this, which is why I'm reposting this here. I'm uncertain how to speak to CLI tools and Java games launched from a macOS app. These sound like security and sandboxing questions which we recommend you ask about in those sections of the forums. The system seems to decide whether to enable Game Mode based on values in the Info.plist (e.g. for LSApplicationCategoryType and GCSupportsGameMode). However, the child process can't seem to see these values. Is there a way to change that? (The rest of this post is copied from my other forums post to provide additional context.) Imagine a native macOS app that acts as a "launcher" for a Java game.** For example, the "launcher" app might use the Swift Process API or a similar method to run the java command line tool (lets assume the user has installed Java themselves) to run the game. I have seen How to Enable Game Mode. If the native launcher app's Info.plist has the following keys set: LSApplicationCategoryType set to public.app-category.games LSSupportsGameMode set to true (for macOS 26+) GCSupportsGameMode set to true The launcher itself can cause Game Mode to activate if the launcher is fullscreened. However, if the launcher opens a Java process that opens a window, then the Java window is fullscreened, Game Mode doesn't seem to activate. In this case activating Game Mode for the launcher itself is unnecessary, but you'd expect Game Mode to activate when the actual game in the Java window is fullscreened. Is there a way to get Game Mode to activate in the latter case? ** The concrete case I'm thinking of is a third-party Minecraft Java Edition launcher, but the issue can also be demonstrated in a sample project (FB13786152). It seems like the official Minecraft launcher is able to do this, though it's not clear how. (Is its bundle identifier hardcoded in the OS to allow for this? Changing a sample app's bundle identifier to be the same as the official Minecraft launcher gets the behavior I want, but obviously this is not a practical solution.)
3
0
140
3w
Getting Progress from long running process
I have been working on updating an old app that makes extensive use of Objective-C's NSTask. Now using Process in Swift, I'm trying to gather updates as the process runs, using readabilityHandler and availableData. However, my process tends to exit before all data has been read. I found this post entitled "Running a Child Process with Standard Input and Output" but it doesn't seem to address gathering output from long-running tasks. Is there a straightforward way to gather ongoing output from a long running task without it prematurely exiting?
10
0
105
May ’25
mac 开发 com.apple.security.application-groups 问题
我在开发 Mac应用完成 后 通过Xcode 上传二进制文件的过程中, 出现了错误, 错误提示: App里面用到的 com.apple.security.application-groups 权限里面 有 group.*** 和 开发者组ID.*** 导致校验失败, 当我单独使用 group.xxx的时候, 我的程序会崩溃 , 因为里面用到了 MachPortRende 进程间通信问题, 这里默认了 开发者组ID.*** 这个路径, 错误详情: 在尝试启动 QuickFox 应用时,程序因权限问题而崩溃。具体的错误信息 bootstrap_check_in 组ID.xxxx.MachPortRendezvousServer.82392: Permission denied (1100) 显示,应用在尝试使用 Mach 端口进行进程间通信时,没有获得足够的权限, 因此 我需要您们的帮助, 如果单独用开发者组ID.*** 我们又没有权限 将数据写入 组ID.xxx里面的文件
1
0
45
Apr ’25
关于本地回环地址调节优先级的问题
你好,是这样的,目的我使用的是mac mini进行软件测试,我目前测试的软件会通过本地回环地址127.0.0.1进行数据传输,这种数据传输不是网络请求,所以用网络抓包的手段,没法测试。所以,我目前的想法是修改您macOS的本地回环地址优先级,定向到我自己的代理服务器,进行数据测试和请求检测。我对liunx系统的作比较了解,但是对于macos上面这方面设置的修改不太清楚。 希望您可以解答!
2
0
43
Apr ’25
CoreAudio server plugin gaining write access with SystemConfiguration.framework functions
Hi, our CourAudio server plugin utilizes the SystemConfiguration.framework to store and restore specific shared system wide settings. While our application can authenticate to utilize the SystemConfiguration.framework to gain write access to the shared configuration settings the CoreAudio server plugin obviously can't have any user interaction and therefor does not authenticate. Is it possible to authenticate the CoreAudio server plugin to gain write permissions? Are there any entitlements or other means that would allow this? Thanks!
2
0
48
Apr ’25
Communicating between app & ui test runner
I'd like to set up a communication mechanism between the Ui test runner and my iOS app. The purpose is to be able to collect some custom performance metrics in addition to standard ones like scrollingAndDecelerationMetric. Let's say we measure some specific intervals in our code using signposts, then serialize the result into a structured payload and report it back to the runner. So, are there any good options for that kind of IPC? The primary concern is running on Simulator. However, since it is not a regular UI test but more a performance UI test, and it is usually recommended to run those on a real device, with release optimizations/flags in place, I wonder if it is feasible to have it for device too.
0
0
346
Feb ’25
Handling XPC Communication to Multiple Clients: Is Storing Connections a Reliable Approach?
This is the functionality I am trying to achieve with libxpc: There's one xpc server and two xpc clients. When the xpc server receives a particular dictionary item from clientB, the server needs to send a response to both clientA and clientB. This is the approach I am currently using: First, clientA creates a dictionary item that indicates that this item is from clientA. Now, clientA sends this dictionary to server. When server receives this item, it stores the connection instance with clientA in a global variable. Next, when clientB sends a particular dictionary item, server uses this global variable where it perviously stored clientA's connection instance to send a response back to clientA, alongside clientB. Only one edge case I can see is that when clientA closes this connection instance, server will be trying to send a response to an invalidated connection. Question: Is this approach recommended? Any edge cases I should be aware of? Is there any better way to achieve this functionality?
2
0
410
Feb ’25
Can we disable KeepAlive temporarily for launchctl?
I have a process [command line cpp application] which i want to run always such as it should relaunch after a crash, after device startup etc. I created a launchd Property List File with KeepAlive true and placed under /Library/LaunchDaemons. Problem Statements: I have a bash script to start and stop this process. start using: launchctl bootstrap. stop involve these two steps: send SIGTERM ****** and wait untill process stops after doing some cleanups launchctl bootout [It doesn't sends SIGTERM] during steps 1 - Process is getting stop, but also getting immediate relaunch by launchctl during step 2 - it getting stop again. is there a proper way so that we can disable KeepAlive temporarily so that process will not launch during step 1? or suggest other ways to handle this?
3
0
731
Nov ’24
Directly operating on memory pointed by UnsafeMutableRawPointer
In my project, i have a Swift class with a class level property of type string. Like this : class TWSwiftString { var pString:String! init(_ pString: String) { self.pString = pString } } I am creating intance of this class and then creating a opaque pointer to this intance. Like this : let str = TWSwiftString("World") // Increasing RC by 1 strptr = Unmanaged.passRetained(str).toOpaque() Now using this opaque pointer i want to modify the value of pString by directly operating on memory. Like this: withUnsafeMutablePointer(to: &strptr.pString) { strPointer in strPointer.pointee = "World" } Although i am able to modify pString like this and print. Lets assume i have a approach to make sure memory remains valid when it is operated on and freeing of memory is also handled somehow . Will this approach work if i have 100s of intance of this string which are being operated in this manner ? What if the size of new value is greater than existing string value ? For this i am thinking of chunk of memory initially and then keep on increasing size of it as bigger string then this chunk comes. Does this approach seems feasible ? Any other problems i can encounter by using this approach ? Chatgpt gave this answer : To directly update the memory of a Swift class’s property, particularly to alter a String property, is generally discouraged due to Swift's memory safety model. However, if we want to access and modify a class property directly, the best practice is to use a property accessor, as manually altering memory could lead to undefined behavior or even crashes. Why Direct Memory Manipulation Is Risky When you attempt to manipulate memory directly, especially with Swift’s memory model, you might alter not only the value but also the memory layout of Swift’s String type, which could break things internally. The Swift compiler may store String differently based on the internal structure, so even if we manage to locate the correct memory address, directly modifying it is unreliable. do you have any opinion around chatgpt resoponse ?
1
0
463
Nov ’24
iOS 18.0.1 - SafariViewService - LIBXPC - XPC_EXIT_REASON_FAULT
Title: SafariViewService Recurring "Hard Refresh" Issue on iOS 18.0.1 Hello, Many of my app users are experiencing a recurring "hard refresh" issue related to SafariViewService, which appears only on iOS 18.0.1 across various iPhone models. Users on earlier iOS versions are not encountering this problem. Our app relies on SafariViewService, and the logs show an event triggered by an EXC_GUARD exception with a termination reason from LIBXPC, causing the app to stop. Below are key details from the log report: App Version: 4.1.2 (build 4.1.1.0) OS Version: iPhone OS 18.0.1 Exception Type: EXC_GUARD Subtype: GUARD_TYPE_USER Termination Reason: LIBXPC, XPC_EXIT_REASON_FAULT Device Model: iPhone 11 Pro Max Process Path: [Removed] Here’s an excerpt from the logs: ... {"codes":"0x6000000000000007, 0x0000000000000009","reason":9,"message":"namespc 7 reason_code 0x0000000000000009","subtype":"GUARD_TYPE_USER","type":"EXC_GUARD","rawCodes":[Removed],"namespc":7}, "termination" : {"flags":518,"code":9,"namespace":"LIBXPC","indicator":"XPC_EXIT_REASON_FAULT"}, ... I would greatly appreciate any guidance on resolving this issue, particularly if there are known concerns with inter-process communication (LIBXPC) in iOS 18.0.1 or advice on how to manage the EXC_GUARD exception more effectively. Full log details are in the attachment. Thank you for your help! ExcUserFault_SafariViewService-2024-10-10-102717 (1).ips ExcUserFault_OnixWorker.Maui-2024-10-10-102718 (1).ips Thank you for your help!
0
8
1.3k
Oct ’24
How does the Endpoint Security Client communicate with the Container APP?
I've developed a Endpoint Security system extension, which will be installed in a container APP. I use XPC to send message from container APP to the ES client, it works fine. I have developed an Endpoint Security system extension that will be installed in a container app. I utilize XPC to send messages from the container app to the ES client, and it functions properly. However, when I attempt to send messages from the ES client to the container app, it always displays an error: 'Couldn’t communicate with a helper application.'. I have removed the sandbox capability of the container app and also employed the same app group for both the ES client and the container app. When an XPC client is connected, I use the following code in the ES client to establish two-way communication. - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection { newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(NXFileGuardXPCProtocol)]; NXFileGuardXPCService *xpcService = [NXFileGuardXPCService sharedInstance]; newConnection.exportedObject = xpcService; // To APP container client (As remote interface) newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(NXFileGuardXPCClientProtocol)]; [newConnection activate]; self.containerAPPConnection = newConnection; return YES; } But it always fails. How can I deal with this error?
2
0
696
Oct ’24
obtaining file creation & modified time & size failing 5-10% of time within .onOpenURL when file shared with app
When users share a file with my app I am having trouble 5-10% of the time obtaining the file meta data, specifically creation and modified time and size. Using SwiftUI with the code below.. .onOpenURL { url in var fileSize: Int64 = 0 var creationTime: Date = Date(timeIntervalSince1970: 0) var modificationTime: Date = Date(timeIntervalSince1970: 0) do { let fileAttributes = try FileManager.default.attributesOfItem(atPath: url.path) fileSize = fileAttributes[FileAttributeKey.size] as? Int64 ?? 0 creationTime = fileAttributes[FileAttributeKey.creationDate] as? Date ?? Date(timeIntervalSince1970: 0) modificationTime = fileAttributes[FileAttributeKey.modificationDate] as? Date ?? Date(timeIntervalSince1970: 0) <SNIPPED CODE no other tries though and not involving above variables> } catch { // quite confident I am ending up here because variables after the above code aren’t being set and there are no other try blocks, // so FileManager.default.attributesOfItem(atPath: url.path) must be throwing…. } <SNIPPED CODE> To attempt to resolve this, I added in a 0.5 second wait cycle if creationTime == 0 and modificationTime == 0 , so if obtaining both metadata fails, wait 0.5 seconds and try again, try this a max of 3 times and then give up. I don’t know how often I am entering this code (didn’t instrument the app for it), but am still getting times when metadata comes back blank which means this code wasn’t successful after 3 tries. I assume the file would only become visible and sharable with my app after it has completed being written by the original app/process. Perhaps it hasn’t finalized yet? Is there a way to detect this so I can tell the user in my share screen to wait and try again? I am assuming that the file has finished writing though since when I read the data from the file contents, it’s good data and complete even when metadata failed. I will be instrumenting the above code in my next app version, just hoping to fix it right now since users are emailing saying my app is broken. Thanks!
3
0
710
Sep ’24
SwiftUI .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) doesn't seem to work
We need to read the value for userActivity.referrerUrl when the app is accessed through a Universal Link, which when using the UIKit lifecycle we can easily do by implementing the method scene(_: UIScene, continue: NSUserActivity) in SceneDelegate and filtering for activity type of NSUserActivityTypeBrowsingWeb. When the app uses the SwiftUI lifecycle that method doesn't get called, even though the app is correctly configured to use AppDelegate and SceneDelegate (through the @UIApplicationDelegateAdaptor wrapper). I can confirm that the setup is correct because the method scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) in SceneDelegate is called on app launch. The obvious SwiftUI way of achieving the same would be by using the .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) modifier, but that doesn't work. Is this a bug?
3
1
987
Aug ’24
Universal Links AASA - not updating on device
Hi all, I wonder if anyone can shed any light or tips on this. We have our iOS app which is just for iPhone at the moment. I have some universal links that are currently working. I have added another '/mobileAppQuickLink' into the file and updated on our site in the '.well-known' folder location. The issue I am having is, all of the links before the additional one mentioned above are working. Steps Checked Checked https://app-site-association.cdn-apple.com/a/v1/OUR_DOMAIN to make sure the latest AASA file is there, it is. Checked the sysdiagnosis package logs and can see in the 'swcutil_show.txt' that only the original three are there for the app and not the final one. Reinstalled the app multiple time to bring down the AASA, no luck. Wiped a device and reset, downloaded the app again, no luck. The code below is the AASA file with our app ID redacted. I have triple checked these and they haven't changed from the previous. "applinks": { "details": [ { "appIDs": [ "A646R8---.com.REDACTED.REDACTED" ], "components": [ { "#": "no_universal_links", "exclude": true, "comment": "Matches any URL with a fragment that equals no_universal_links and instructs the system not to open it as a universal link." }, { "/": "/client/*", "comment": "Matches any URL with a path that starts with /client/." }, { "/": "/files/*", "comment": "Matches any URL with a path that starts with /files/." }, { "/": "/signingRequests/*", "comment": "Matches any URL with a path that starts with /signingRequests/." }, { "/": "/mobileAppQuickLink" //MISSING ON DEVICE } ] } ] }, "webcredentials": { "apps": [ "A646R8----com.REDACTED.REDACTED" ] } } Below is a copy of one of the 'swcutil_show.txt' from a device. App ID: A646R8----.com.REDACTED.REDACTED App Version: 1.1.70 App PI: <LSPersistentIdentifier 0x88c027a80> { v = 0, t = 0x8, u = 0x548, db = 514601C3-79C8-47C6-A178-B09AF5C-----, {length = 8, bytes = 0x4805000000000000} } Domain: *.portal.staging.REDACTED.REDACTED Patterns: {"#":"no_universal_links","exclude":true}, {"/":"/client/*"}, {"/":"/files/*"}, {"/":"/signingRequests/*"} User Approval: unspecified Site/Fmwk Approval: approved Flags: Last Checked: 2024-08-04 09:44:07 +0000 Next Check: 2024-08-09 09:39:26 +0000 Does anyone know of any reason this could be? It looks like the devices maybe getting a cached version.
2
0
765
Aug ’24
Share arbitrary struct from HostApp to Extension and get arbitrary result back
I want to share a Transferable (JSON-encoded) data struct from some HostApp with an Extension of my ContainingApp, and get a different Transferable (also JSON-encoded) data struct back on success. Since I want to present my ContainingApp's AppIcon in the sharing sheet to make it easy for the user to find it, I started building a Sharing Extension and not an Action Extension. AFAIK the difference is only in the presentation (Sharing Extension: Icon+name of the ContainingApp vs Action Extension: simple b/w system icon plus a string describing the action (e.g. "Copy", "Save to Files")), and the data flow is identical. Please correct me if I'm wrong. I added the Sharing Extension to my ContainingApp (which are both in the same app group so they can use a shared container to exchange data). The (real) HostApp is from a different company we are collaborating with, and thus is not in our app group. Once everything runs I will add a tailored NSExtensionActivationRule to make sure our Sharing Extension is only shown to our partner's HostApp. Currently I am still using TRUEPREDICATE. The goal is that after the user tapped the "Continue with ContainingApp" (Share-)button in the HostApp, iOS will only show my ContainingApp icon and nothing else, since that's the only useful choice for the user. Side Question 1: The best user experience would be if the HostApp could directly present our extension when the user tapped the "Continue with ContainingApp"-button, without the user needing to choose it manually in the Share-sheet, but I guess this is not possible for privacy/security reasons, right? In the debugger of the HostApp I see this error: Type "com.myapp.shareInput" was expected to be exported in the Info.plist of Host.app, but it was imported instead. Library: UniformTypeIdentifiers | Subsystem: com.apple.runtime-issues | Category: Type Declaration Issues but I definitely want to define and export both ShareInput and ShareResult as UTExportedTypeDeclarations in my extension, and all 3rd-party apps (like this demo HostApp) using my extension need to import them. Side Question 2: Can I just ignore this error? And tell the 3rd-party app developers they also can ignore it? After the user tapped on the ContainingApp icon in the sharing dialog, my Sharing Extension will show its dialog, presenting the shared item it got from the HostApp, and let the user edit the text. When the user taps the "Save"-button in my extension, it creates a ShareResult struct to send back to the HostApp, and dismisses the sheet. This (kinda) works when I share plain text with the 􀈂Text button in my HostApp. My ContainingApp icon is shown together with Mail, Messages, and other apps that can process plain text; with shortcuts to persons and devices (AirDrop targets) in the line above, and with actions (Copy, New Quick Note, Save to Files, Save to Citator, Certificat, Airdrop) below. When I choose my ContainingApp, the extension runs and shows the text it got. ("Kinda" because I am still struggling to send data back. See below...) So the principal operation works... Side Question 3: In the HostApp, can I use ShareLink() to present the Share-sheet and receive the result struct or do I always need to activityViewController!.completionWithItemsHandler = completionHandler windowScene.keyWindow?.rootViewController?.present(activityViewController!, animated: true, completion: nil) and process the result in the completionHandler? If returning (any) data from the extension is possible with ShareLink() also, then how? I didn't find any sample showing this... I implemented the ShareLink() anyway (and ignore the result part for the moment). When I try to share a ShareInput struct with the 􀈂ShareLink button, the same persons are sorted differently, there are less app icons (9 instead of 13), and less actions (only 3: New Quick Note, Save to Files, AirDrop): Note that while the preview correctly shows the preview text provided ("shareInput"), the preview image left of it is blank (instead of arrowshape.right.fill): let preview = SharePreview("shareInput", image: Image(systemName: "arrowshape.right.fill")) When I choose my ContainingApp, the extension runs ... On iOS17, I see that indeed my ShareInput data arrived in my extension: ❗️itemProvider=<NSItemProvider: 0x301b1c460> {types = ( "com.myapp.shareInput" )} Library: ShareExtension | Subsystem: com.myapp.containingdemo.ShareExtensionDemo | Category: ShareSheet However, on iOS 16 it doesn't work: Host[8615:634470] [Type Declaration Issues] Type "com.myapp.shareInput" was expected to be exported in the Info.plist of Host.app, but it was imported instead. Host[8615:634462] [ShareSheet] Couldn't load file URL for Collaboration Item Provider:<NSItemProvider: 0x280f49180> {types = ( "com.myapp.shareInput" )} : (null) That error is shown before I choose the ContainingApp to share with. When I do that, I get: ShareExtension[8774:636786] [ShareSheet] ❗️itemProvider=<NSItemProvider: 0x28243a300> {types = ( "dyn.age8u", "public.file-url" )} which clearly shows the ShareInput struct was not transferred to the extension. But since I don't know how to transfer the ShareResult back to the HostApp when using a ShareLink, I cannot continue this approach anyway. When I try to share a ShareInput struct with the 􀈂JSON button (using present(activityViewController)), I see (both on iOS 16 and iOS 17): My extension (rather, the ContainingApp's icon) is not shown as Sharing target (even though it still has TRUEPREDICATE), which means that my code didn't manage to pack the ShareInput struct for the activityViewController - and thus it doesn't know what to share. I did the same as with the plainText item before: let shareInput = ShareInput(inputStr: "ShareInput as JSON") let preview = SharePreview("shareInput", image: Image(systemName: "arrowshape.right.fill")) VStack(spacing: 25.0) { Text("HostApp!") ShareButton(title: "Text", shareItems: [ItemSource(dataToShare: "sharing some text")]) ShareButton(title: "JSON", shareItems: [ItemSource(dataToShare: shareInput)]) ShareLink("ShareLink", item: shareInput, preview: preview) } (I will continue in the next posting)
15
0
1.5k
Aug ’24
Migrating from pkg installer to Service Management
Hello, we are currently working on a plan to migrate our app suite from Developer ID binaries inside a simple pkg installer to macOS app store distribution. The reason we are using an installer is that there are multiple binaries inside that communicate via XPC and we need to install the respective launchd plist in /Library/LaunchDaemons and /Library/LaunchAgents: 1 root daemon 1 agent that has minimal UI and lives in the system menu bar 1 embedded command line utility in user agent 1 embedded FileProvider extension in user agent 1 embedded Action Extension in user agent 1 agent that only does OAuth stuff Looking through Updating helper executables from earlier versions of macOS I can install the root daemon with SMAppService.daemon(plistName:) and the OAuth helper with SMAppService.agent(plistName:). For the main application I only found SMAppService.mainApp which does not accept a property list configuration. Therefore, I have no place to put my MachServices array and so the File Provider extension, the Action Extension, and the embedded command line utility have no way to talk to the user agent. Currently, XPC is used in between these processes: user agent -> root daemon command line utility -> user agent action extension -> user agent file provider extension -> user agent user agent -> file provider extension: that already works through NSFileProviderServicing I know app-to-app communication only works through launchd for security reasons, but these applications are all part of the same app group (except the root daemon obviously). My question is what is the proper way of starting the user agent so XPC from other binaries just work ™️? Any input is much appreciated!
6
0
1.3k
Sep ’24
task_for_pid error 5
I'm trying to use task_for_pid in a project but I keep getting error code 5 signaling some kind of signing error. Even with this script I cant seem to get it to work. #include <mach/mach_types.h> #include <stdlib.h> #include <mach/mach.h> #include <mach/mach_error.h> #include <mach/mach_traps.h> #include <stdio.h> int main(int argc, const char * argv[]) {   task_t task;   pid_t pid = argc >= 2 ? atoi(argv[1]) : 1;   kern_return_t error = task_for_pid(mach_task_self(), pid, &task);   printf("%d -> %x [%d - %s]\n", pid, task, error, mach_error_string(error));   return error; } I've tried signing my executables using codesign and also tried building with Xcode with the "Debugging Tool" box checked under hardened runtime. My Info.plist file includes the SecTaskAccess key with the values "allowed" and "debug." Hoping someone can point me towards what I'm missing here. Thanks!
4
0
3.4k
Nov ’24
Running a Child Process with Standard Input and Output
IMPORTANT Rather than use the code below, I recommend that you adopt Swift’s shiny-new Subprocess package. That’s what I’m doing! (-: Running a child process using Process (or NSTask in Objective-C) is easy, but piping data to and from the child’s stdin and stdout is surprisingly tricky. I regularly see folks confused by this. Moreover, it’s easy to come up with a solution that works most of the time, but suffers from weird problems that only show up in the field [1]. I recently had a couple of DTS incidents from folks struggling with this, so I sat down and worked through the details. Pasted below is the results of that effort, namely, a single function that will start a child process, pass it some data on stdin, read the data from the child’s stdout, and call a completion handler when everything is done. There are some things to note here, some obvious, some not so much: I’ve included Swift and Objective-C versions of the code. Both versions work the same way. The Swift version has all the comments. If you decide to base your code on the Objective-C version, copy the comments from there. I didn’t bother collecting stderr. That’s not necessary in many cases and, if you need it, it’s not hard to extend the code to handle that case. I use Dispatch I/O rather than FileHandle to manage the I/O channels. Dispatch I/O is well suited to this task. In contrast, FileHandle has numerous problems working with pipes. For the details, see Whither FileHandle?. This single function is way longer than I’d normally tolerate. This is partly due to the extensive comments and party due to my desire to maintain focus. When wrapping Process it’s very easy to run afoul of architecture astronaut-ism. Indeed, I have a much more full-featured Process wrapper sitting on my hard disk, but that’s going to stay there in favour of this approach (-: Handling a child process correctly involves some gnarly race conditions. The code has extensive comments explaining how I deal with those. If you have any questions or comments about this, put them in a new thread. Make sure to tag that thread with Foundation and Inter-process communication so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] Indeed, this post shows that I’ve made this sort of mistake myself )-:
2
0
7.5k
Apr ’25