Processes & Concurrency

RSS for tag

Discover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.

Concurrency Documentation

Posts under Processes & Concurrency subtopic

Post

Replies

Boosts

Views

Activity

Best practice for replacing deprecated sem_init/sem_wait in a cross-platform threading layer on macOS (arm64)
Hi all, I'm working on a cross-platform runtime that manages a pool of threads (think game engine / emulator style... dozens of guest threads mapped 1:1 to host pthreads). It was originally written for Linux and Windows and we're now porting to macOS on Apple Silicon. We've hit a wall with a deadlock on macOS and traced it back to our use of POSIX unnamed semaphores (sem_init / sem_wait / sem_post) for thread suspend and resume. We were unaware these have never actually been implemented on macOS, sem_init silently returns -1 with ENOSYS and then sem_wait just hangs forever. That explains our deadlock. The tricky part is how we use them. Our suspend mechanism works by sending SIGUSR1 to a target thread via pthread_kill. The signal handler then calls sem_wait to block the thread in place until another thread calls sem_post to resume it. So whatever we replace sem_init/sem_wait with needs to be safe to call from inside a signal handler. From what I can tell: dispatch_semaphore_wait is not documented as async-signal-safe pthread_cond_wait is also not async-signal-safe os_sync_wait_on_address looks promising but requires macOS 14.4+ which is a pretty high floor We could spin on a std::atomic with .wait() / .notify_all() but I've seen reports of high wake latency (up to 15ms) in libc++'s implementation on macOS My questions: What's the recommended way to block a thread inside a signal handler on macOS? Is there an async-signal-safe wait primitive I'm missing? Would restructuring to avoid blocking in the signal handler entirely be the better approach? For example, having the signal handler just set an atomic flag and then checking it at yield points — would that be the expected pattern on macOS? For the non-signal-handler suspend/resume paths, is dispatch_semaphore_t the right replacement for sem_t, or is there something better suited for high-frequency thread synchronization in 2026? Separately, we're also using ucontext (makecontext/swapcontext) for a fiber system on macOS and hitting issues on native arm64, it works under Rosetta but breaks natively. We have a setjmp/longjmp + manual stack pivot backend we can switch to. Is there any plan to fix or un-deprecate the ucontext functions on arm64, or should we just move off them permanently?
2
0
173
3w
SMAppService - helper is not started
My software installs a privileged daemon using the SMAppService api. After removing the executables and recompiling the software I sometimes find that it needs to be registered again. After doing this, i.e. ensuring the application is properly registered and enabled in Login Items & Extensions the helper is not run when initiated from XPC. SMAppService.status has returned .enabled, and there is a valid job dictionary for the helper. I check the job dictionary with a function called updatePenaltyBoxStatus() that was given to me by a friend but I think originated from Apple. If I logoff (or reboot), login again, manually open Login Items & Extensions to check registration, then retry the application, it works. I don't mind doing this but it is probably a bit much for a lot of my users. Is there a reliable way to do this programatically? Here is my Swift translation of updatePenaltyBoxStatus. I fetch the job dictionary with SMJobCopyDictionary() prior to calling isInPenaltyBox(). I also had to write C wrapper functions for the WIFEXITED and WIFEXITSTATUS macros. func isInPenaltyBox(_ dict: Dictionary<String, Any>?) -> Bool { guard let jobDict = dict else { // If the helper was in the penalty box, unregistering it doesn't change that. So don't override a previous helperInPenaltyBox value return m_penalty_box } if let lastExitStatusObj = jobDict["LastExitStatus"] as? NSNumber { let lastExitStatus = lastExitStatusObj.intValue if wifexited(Int32(lastExitStatus)) == 0 { // It might've stopped or exited due to a signal or whatever. // Regardless, it didn't meet our criteria for winding up in the penalty box. m_penalty_box = false } // Now get the exit status and check for `EX_CONFIG`. let status = wexitstatus(Int32(lastExitStatus)) let newInPenaltyBox = status == EX_CONFIG if m_penalty_box != newInPenaltyBox { Logger.instance.log( "Penalty box change: " + m_ident + " old: " + String(m_penalty_box) + " new: " + String(newInPenaltyBox)) } m_penalty_box = newInPenaltyBox } return m_penalty_box }
2
0
211
1w
App Terminated with 0x8BADF00D: Main Thread Blocked During Back-to-Back Messaging
Hello, I'm experiencing an issue with my app where it's being terminated by the system with a watchdog violation during back-to-back messaging operations. I've analyzed the crash logs but would appreciate additional insights on optimizing my approach. I'd appreciate any insights on how to resolve this problem. Crash Details: Exception Type: EXC_CRASH (SIGKILL) Termination Reason: FRONTBOARD with code 0x8BADF00D Error: "scene-update watchdog transgression: app exhausted real time allowance of 10.00 seconds" Reproduction Steps: User A initiates back-to-back messages to other User User A's UI becomes unresponsive and eventually the app crashes. Stack Trace Analysis: The crash occurs on the main thread, which appears to be blocked waiting for a condition in the keyboard handling system. The thread is stuck in [UIKeyboardTaskQueue _lockWhenReadyForMainThread] and related methods, suggesting an issue with keyboard-related operations during the messaging process. Crash Tag Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: FRONTBOARD 2343432205 <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-update watchdog transgression: app<com.msikodiak.eptt(AD934F8A-DF57-4B75-BE73-8CF1A9A8F856)>:301 exhausted real (wall clock) time allowance of 10.00 seconds ProcessVisibility: Foreground ProcessState: Running WatchdogEvent: scene-update WatchdogVisibility: Background WatchdogCPUStatistics: ( "Elapsed total CPU time (seconds): 6.390 (user 3.640, system 2.750), 11% CPU", "Elapsed application CPU time (seconds): 0.020, 0% CPU" ) ThermalInfo: ( "Thermal Level: 0", "Thermal State: nominal" ) reportType:CrashLog maxTerminationResistance:Interactive> Triggered by Thread: 0 Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 libsystem_kernel.dylib 0x1e773d438 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x2210bc328 _pthread_cond_wait + 1028 2 Foundation 0x1957d8a64 -[NSCondition waitUntilDate:] + 132 3 Foundation 0x1957d8888 -[NSConditionLock lockWhenCondition:beforeDate:] + 80 4 UIKitCore 0x1998f1238 -[UIKeyboardTaskQueue _lockWhenReadyForMainThread] + 456 5 UIKitCore 0x19a3d775c __59-[UIKeyboardImpl updateAutocorrectPrompt:executionContext:]_block_invoke_9 + 28 6 UIKitCore 0x19986b084 -[UIKeyboardTaskQueue lockWhenReadyForMainThread] + 168 7 UIKitCore 0x19a3f2994 -[UIKeyboardTaskQueue waitUntilTaskIsFinished:] + 148 8 UIKitCore 0x19a3f2ac4 -[UIKeyboardTaskQueue performSingleTask:breadcrumb:] + 132 9 UIKitCore 0x199e2f7e4 -[_UIKeyboardStateManager updateForChangedSelection] + 144 10 UIKitCore 0x199e24200 -[_UIKeyboardStateManager invalidateTextEntryContextForTextInput:] + 92 11 WebKit 0x1ad52fa54 WebKit::PageClientImpl::didProgrammaticallyClearFocusedElement(WebCore::ElementContext&&) + 40 12 WebKit 0x1ad55adcc WebKit::WebPageProxy::didProgrammaticallyClearFocusedElement(WebCore::ElementContext&&) + 136 13 WebKit 0x1acec74e8 WebKit::WebPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 18604 14 WebKit 0x1acd21184 IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 236 15 WebKit 0x1ace449b8 WebKit::WebProcessProxy::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 40 16 WebKit 0x1ace44228 WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 1764 17 WebKit 0x1acd1e904 IPC::Connection::dispatchMessage(WTF::UniqueRef<IPC::Decoder>) + 268 18 WebKit 0x1acd1e478 IPC::Connection::dispatchIncomingMessages() + 576 19 JavaScriptCore 0x1ae386b8c WTF::RunLoop::performWork() + 524 20 JavaScriptCore 0x1ae386960 WTF::RunLoop::performWork(void*) + 36 21 CoreFoundation 0x196badce4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 22 CoreFoundation 0x196badc78 __CFRunLoopDoSource0 + 172 23 CoreFoundation 0x196bac9fc __CFRunLoopDoSources0 + 232 24 CoreFoundation 0x196babc3c __CFRunLoopRun + 840 25 CoreFoundation 0x196bd0700 CFRunLoopRunSpecific + 572 26 GraphicsServices 0x1e3711190 GSEventRunModal + 168 27 UIKitCore 0x1997ee240 -[UIApplication _run] + 816 28 UIKitCore 0x1997ec470 UIApplicationMain + 336 29 Telstra PTT 0x1004d30c8 main + 56 30 dyld 0x1bd5d3ad8 start + 5964
4
1
435
Oct ’25
Does BGAppRefreshTask require an internet connection?
Basically the title. I am trying to implement a local notification to trigger, regardless of internet connection, around 3-5pm if a certain array in the app is not empty to get the user to sync unsaved work with the cloud. I wanted to used the BGAppRefreshTask as I saw it was lightweight and quick for just posting a banner notification but after inspecting it in the console, it looks like it needs internet connection to trigger. Is this the case or am I doing something wrong? Should I be using the BGProcessingTask instead?
1
0
139
Jul ’25
[iOS 26 Beta] BGTaskScheduler.supportedResources incorrectly reports no GPU support for BGContinuedProcessingTask on capable hardware
Testing Environment: iOS: 26.0 Beta 7 Xcode: Beta 6 Description: We are implementing the new BGContinuedProcessingTask API introduced in iOS 26. We have followed the official documentation and WWDC session guidance to configure our project. The Background Modes (processing) and Background GPU Access capabilities have been added in Xcode. The com.apple.developer.background-tasks.continued-processing.gpu entitlement is present and set to in the .entitlements file. The provisioning profile details viewed within Xcode explicitly show that the "Background GPU Access" capability and the corresponding entitlement are included. Despite this correct configuration, when running the app on supported hardware (iPhone 16 Pro), a call to BGTaskScheduler.supportedResources.contains(.gpu) consistently returns false. This prevents us from setting request.requiredResources = .gpu. As a result, when the BGContinuedProcessingTask starts without the GPU resource flag, our internal Metal-based exporter attempts to access the GPU and is terminated by the system, throwing an IOGPUMetalError: Insufficient Permission (to submit GPU work from background). We have performed extensive debugging, including a full reset of the provisioning profile (removing/re-adding capabilities, toggling automatic signing, cleaning build folders, and reinstalling the app), but the issue persists. This strongly suggests a bug in the iOS 26 beta where the runtime is failing to correctly validate a valid entitlement. Additionally, we've observed inconsistent behavior across devices. On an A16-based iPad, the task submits successfully (BGTaskScheduler.submit does not throw an error), but the launch handler is never invoked by the system. On the iPhone 16 Pro, the handler is invoked, but we encounter the supportedResources issue described above. This leads us to ask for clarification on the exact hardware requirements for this feature. We hypothesize that it may be limited to devices that support Apple Intelligence (A17 Pro and newer). Could you please confirm this and provide official documentation on the device support criteria? Steps to Reproduce: Create a new Xcode project. In Signing & Capabilities, add "Background Modes" (with "Background processing" checked) and "Background GPU Access". Add a permitted identifier (e.g., "com.company.test.*") to BGTaskSchedulerPermittedIdentifiers in Info.plist. In application(_:didFinishLaunchingWithOptions:) or a ViewController's viewDidLoad, log the result of BGTaskScheduler.shared.supportedResources.contains(.gpu). Build and run on a physical, supported device (e.g., iPhone 16 Pro). Expected Results: The log should indicate that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns true. Actual Results: The log shows that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns false.
6
0
888
Dec ’25
Stay connected to Medical BLE device in background
I work for a large medical device company. We have a 1st party BLE enabled medical device that must be very battery efficient. To this end, if a connection is lost, the BLE radio is powered down after 60 seconds and will only turn back on when a physical button on the device is pressed. I've been tasked with connecting to the device, staying connected to the device, and being able to retrieve data from the device upon a timed action. For instance, this could include a data read and transmission while they sleep. The key part of this is staying reliably connected for extended periods of time. This is a BYOD setup, and we cannot control power profiles. I would very much appreciate any information, recommendations, and/or insights into solving this problem. Thanks!
1
0
513
Sep ’25
How to detect or opt out of iOS app prewarming?
Hi, We are running into issues with iOS app prewarming, where the system launches our app before the user has entered their passcode. In our case, the app stores flags, counters, and session data in UserDefaults and the Keychain. During prewarm launches: UserDefaults only returns default values (nil, 0, false). We have no way of knowing whether this information is valid or just a placeholder caused by prewarming. Keychain items with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly are inaccessible, which can lead to broken business logic (the app can assume no session exists). No special launch options or environment variables appear to be set. We can reproduce this 100% of the time by starting a Live Activity in the app before reboot. Here’s an example of the workaround we tried, following older recommendations: __attribute__((constructor)) static void ModuleInitializer(void) { char* isPrewarm = getenv("ActivePrewarm"); if (isPrewarm != NULL && isPrewarm[0] == '1') { exit(0); // prevent prewarm launch from proceeding } } On iOS 16+, the ActivePrewarm environment variable doesn’t seem to exist anymore (though older docs and SDKs such as Sentry reference it). We also tried listening for UIApplication.protectedDataDidBecomeAvailableNotification, but this is not specific to prewarming (it also fires when the device gets unlocked) and can cause watchdog termination if we delay work too long. Questions: Is there a supported way to opt out of app prewarming? What is the correct way to detect when an app is being prewarmed? Is the ActivePrewarm environment variable still supported in iOS 16+? Ideally, the UserDefaults API itself should indicate whether it is returning valid stored values or defaults due to the app being launched in a prewarm session. We understand opting out may impact performance, but data security and integrity are our priority. Any guidance would be greatly appreciated.
1
0
244
Oct ’25
SSO Extension Fails XPC Connection to System Daemon (mach-lookup exception used)
Hello, I'm running into an issue with a complex macOS application (non-AppStore) structure involving an unsandboxed system daemon and a sandboxed SSO Extension attempting to communicate via XPC Mach service. The macOS app is composed of three main components: Main App: unsandboxed, standard macOS application. System Daemon: unsandboxed executable installed with a .plist to /Library/LaunchDaemons/ and loaded by launchd. It exposes an XPC Mach Service. SSO Extension: a sandboxed Authentication Services Extension (ASAuthorizationProviderExtension). Main App to System Daemon communication works perfectly. The unsandboxed main app can successfully create and use an XPC connection to the System Daemon's Mach service. But SSO Extension cannot establish an XPC connection to the System Daemon's Mach service, despite using the recommended temporary exception entitlement. I have added the following entitlement to the SSO Extension's entitlements file: <key>com.apple.security.temporary-exception.mach-lookup.global-name</key> <array> <string>my.xpc.service.system.daemon</string> </array> (The name my.xpc.service.system.daemon is the exact name registered by the System Daemon in its Launch Daemon plist's MachServices dictionary.) When the SSO Extension attempts to create the connection, the following log output is generated: default 08:11:58.531567-0700 SSOExtension [0x13f19b090] activating connection: mach=true listener=false peer=false name=my.xpc.service.system.daemon default 08:11:58.532150-0700 smd [0xb100d8140] activating connection: mach=false listener=false peer=true name=com.apple.xpc.smd.peer[1575].0xb100d8140 error 08:11:58.532613-0700 smd Item real path failed. Maybe the item has been deleted? error 08:11:58.532711-0700 SSOExtension Unable to find service status () error: 22 The error Unable to find service status () error: 22. Error code 22 typically translates to EINVAL (Invalid argument), but in this context, it seems related to the system's ability to find and activate the service for the sandboxed process. Questions: Is the com.apple.security.temporary-exception.mach-lookup.global-name entitlement sufficient for a sandboxed SSO Extension to look up a system-wide Launch Daemon Mach service, or are there additional restrictions or required entitlements for extensions? The smd log output Item real path failed. Maybe the item has been deleted? seems concerning. Since the unsandboxed main app can connect, this suggests the service is running and registered. Could this error indicate a sandbox permission issue preventing smd from verifying the path for the sandboxed process? Are there specific sandboxing requirements for Mach service names when communicating from an Extension versus a main application? Any guidance on how a sandboxed SSO Extension can reliably connect to an unsandboxed, non-app-group-related system daemon via XPC Mach service would be greatly appreciated!
2
0
289
Oct ’25
Recursively walk a directory using File Coordination
What’s the recommended way to recursively walk through a directory tree using File Coordination? From what I understand, coordinating a read of a directory only performs a “shallow” lock; this would mean that I’d need to implement the recursive walk myself rather than use FileManager.enumerator(at:includingPropertiesForKeys:options:errorHandler:) plus a single NSFileCoordinator.coordinate(with:queue:byAccessor:) call. I’m trying to extract information from all files of a particular type, so I think using NSFileCoordinator.ReadingOptions.immediatelyAvailableMetadataOnly on each file before acquiring a full read lock on it (if it’s the right file type) would make sense. Am I on the right track?
5
0
180
Oct ’25
What is the new name of the OSDUIHelper process on macOS Tahoe?
I am currently developing a macOS app that can show system HUDs in the Notch Till Sequoia I used to kill the OSDUIHelper process (which displays the default macOS Volume and Brightness control HUDs) - and replaced it with my app's HUDs But, it is not working on macOS Tahoe anymore as the OSDUIHelper process is no longer there due to the UI changes Has the process been renamed - or is there any other way to kill the process?
1
0
180
Oct ’25
Bluetooth work with BGTaskScheduler
Hi All, I'm working on an app that needs to connect to BLE device and on defined schedules download data from the device. the amount of data is segnificant and might take around a minute to download. we tought about utilizing both state restoration and preservation for app waking and scheduling (triggered by the ble peripheral) and BGTaskScheduler to schedule a task that will handle a long running task to manage the full data download. now, will this solution in general valid? isnt it a "hack" that goes around the 10s limit that state restoration enforces? i know there are limitations for BGTask (like when it runs, it might be terminated by the system etc) but considering that, can we proceed with this approach without breaching apple guidelines? thank you in advance!
2
0
232
Oct ’25
Does Mac Catalyst support Background Processing?
I have an app for macOS that is built using Mac Catalyst. I need to perform some background processing. I'm using BGProcessingTaskRequest to schedule the request. I have also integrated CKSyncEngine so I need that to be able to perform its normal background processing. On iOS, when the user leaves the app, I can see a log message that the request was scheduled and a bit later I see log messages coming from the actual background task code. On macOS I ran the app from Xcode. I then quit the app (Cmd-q). I can see the log message that the request was scheduled. But the actual task is never run. In my test, I ran my app on a MacBook Pro running macOS 26.0. When I quit the app, I checked the log file in the app sandbox and saw the message that the task was scheduled. About 20 minutes later I closed the lid on the MacBook Pro for the night. I did not power down, it just went to sleep. Roughly 10 hours later I opened the lid on the MacBook Pro, logged in, and checked the log file. It had not been updated since quitting the app. I should also mention that the laptop was not plugged in at all during this period. My question is, does a Mac Catalyst app support background processing after the user quits the app? If so, how is it enabled? The documentation for BGProcessingTaskRequest and BGProcessingTask show they are supported under Mac Catalyst, but I couldn't find any documentation in the Background Tasks section that mentioned anything specific to setup for Mac Catalyst. Running the Settings app and going to General -> Login Items & Extension, I do not see my app under the App Background Activity section. Does it need to be listed there? If so, what steps are needed to get it there? If this is all documented somewhere, I'd appreciate a link since I was not able to find anything specific to making this work under Mac Catalyst.
4
1
313
Nov ’25
NotificationCenter.notifications(named:) appears to buffer internally and can drop notifications, but is this documented anywhere?
I've experimentally seen that the notifications(named:) API of NotificationCenter appears to buffer observed notifications internally. In local testing it appears to be limited to 8 messages. I've been unable to find any documentation of this fact, and the behavior seems like it could lead to software bugs if code is not expecting notifications to potentially be dropped. Is this behavior expected and documented somewhere? Here is a sample program demonstrating the behavioral difference between the Combine and AsyncSequence-based notification observations: @Test nonisolated func testNotificationRace() async throws { let testName = Notification.Name("TestNotification") let notificationCount = 100 var observedAsyncIDs = [Int]() var observedCombineIDs = [Int]() let subscribe = Task { @MainActor in print("setting up observer...") let token = NotificationCenter.default.publisher(for: testName) .sink { value in let id = value.userInfo?["id"] as! Int observedCombineIDs.append(id) print("🚜 observed note with id: \(id)") } defer { extendLifetime(token) } for await note in NotificationCenter.default.notifications(named: testName) { let id: Int = note.userInfo?["id"] as! Int print("🚰 observed note with id: \(id)") observedAsyncIDs.append(id) if id == notificationCount { break } } } let post = Task { @MainActor in for i in 1...notificationCount { NotificationCenter.default.post( name: testName, object: nil, userInfo: ["id": i] ) } } _ = await (post.value, subscribe.value) #expect(observedAsyncIDs.count == notificationCount) // 🛑 Expectation failed: (observedAsyncIDs.count → 8) == (notificationCount → 100) #expect(observedCombineIDs == Array(1...notificationCount)) print("done") }
2
0
311
Dec ’25
ExtensionFoundation/ExtensionKit across app boundary
Hi there, I'm trying to work on an architecture where one app exposes an API (Extension Host) that other apps can plugin to. I've been reading all I can from the docs and whatever I can find online. It seemed like iOS26 added the ability to do such a thing (at least in early builds). Is that the case? Has the functionality been walked back such that extensions can only be loaded in iOS from within the single app bundle? My use case is the following: I'm working on an agent app that desires to have 3rd party developers add functionality (think how MCP servers add functionality to LLMs). The 3rd party plugins would be provided in their own app bundles vetted by the AppStore review team, of course, and would only provide hooks, basically, the main app can use to execute functions or get state. This is the best thread I found on the topic, and the subtext is that it needs to be in the same bundle. https://developer.apple.com/forums/thread/803896?answerId=865314022#865314022 Let's say for the moment that this isn't possible using ExtensionKit. What's the best way to achieve this? Our current best alternative idea is a hidded WebKit window that runs JS/WASM but that's so hackish. Please let me know, thanks!
3
0
276
Dec ’25
Background upload issue in WatchOS
We are developing a watchOS application that records long audio sessions and uploads them to our backend in chunks (~5 MB each) using pre-signed URLs and URLSession background upload. Current behavior: While audio recording is active, uploads continue successfully even when the app is in the background. Once the recording stops, if multiple chunks (e.g., 10+) are still pending, the remaining uploads do not proceed in the background and appear to be suspended. We attempted to use WKExtendedRuntimeSession (mindfulness type) to allow sufficient time to enqueue background upload tasks, but the session is invalidated when the app goes to the background (e.g., wrist down or app inactive), which prevents reliable scheduling of uploads. Additionally, we added the entitlement: com.apple.developer.extended-runtime-session (mindfulness) in the Watch app entitlements file, but Xcode automatic signing fails with: “Provisioning profile does not include the com.apple.developer.extended-runtime-session entitlement.” It appears that the provisioning profile is not being updated to include this entitlement. Our questions: Is WKExtendedRuntimeSession (mindfulness) expected to support scheduling background URLSession uploads after the app goes to background? How should we reliably complete pending background uploads on watchOS after a long recording session ends? Is there any additional entitlement or recommended approach for this use case? Why is the extended runtime entitlement not being applied to the provisioning profile despite being added in the entitlements file? We are aiming to follow Apple-recommended practices for long-running tasks and background uploads on watchOS. Any guidance would be greatly appreciated.
2
0
351
Mar ’26
iOS: Issues getting beginBackgroundTaskWithName working reliably
We have tried using background tasks for file saving via (UIBackgroundTaskIdentifier) beginBackgroundTaskWithName:(NSString *) taskName expirationHandler:(void (^)(void)) handler; when our app goes into the background and/or is closed by the user. But we cannot make it work the way the documentation tells us it should. While task creation never reports an issue (in fact it never calls our expiration handler at all) and the returned task id is always valid, when we ask for how much time we have left via backgroundTimeRemaining we always get 6s instead of the specified 30s. We tried to create the task when the app state goes to inactive or when our delegate is called via applicationDidEnterBackground but it makes no difference, besides the fact that the remaining time reported is basically max double, when the app is not in background yet which is by design as far we understand. But we don't even get the 6s for saving when a user closes the app. Because almost immediately after applicationDidEnterBackground our delegate is called via applicationWillTerminate which will then again almost immediately end in the app receiving a SIGKILL. So we must be doing something wrong. Why would applicationWillTerminate be called at all when we have a valid background task that reports we have 6s left? We tried blocking the thread in both background and terminate to at least give us the 5s the spec says we have before we get the SIGKILL. That works in general but doesn't feel like the correct approach and we do need more time than the 5s or 6s we get this way. Are we supposed to add something to our plist in order for these background tasks to work correctly? It is very confusing that there is a second mechanism that's also called background tasks for running apps in the background in general, which is not applicable to us. Are we supposed to block somewhere when we create the task? Or even spin up an extra thread for the task? Why is our expirationHandler never called? The spec says that our handler should be called if it was unable to "grant the ask assertion" so it seems like we do not have that problem. But it's also supposed to be called just before we are running out of time but by that time the app is already dead. This was all tested on iOS 26.3 and it is probably worth mentioning that our app is Qt-based.
4
0
216
4w
applicationWillTerminate to wrap up Background Recording
Hello together, the user is able to do recordings with my app. The recordings also runs, while the App is in Background. I have Background Modes Audio & Background enabled. When the user accidentally terminates the App while the recording is still running, the whole recording is lost. I tried AppDelegate applicationWillTerminate on my iOS 26 App and it works perfectly to wrap up the LiveActivity that is shown while the recording is active. But it does not save the Audio and also doesn't update the Widgets (they are interactive and show a different state while recording and stay stuck in recording-state on accidental termination). Any ideas? Best wishes, Dominik
2
0
148
1w
Privileged helper without SMJobBless
To establish a privileged helper daemon from a command line app to handle actions requiring root privileges I still use the old way of SMJobBless. But this is deprecated since OSX 10.13 and I want to finally update it to the new way using SMAppService. As I'm concerned with securing it against malicious exploits, do you have a recommended up-to-date implementation in Objective-C establishing a privileged helper and verifying it is only used by my signed app? I've seen the suggestion in the documentation to use SMAppService, but couldn't find a good implementation covering security aspects. My old implementation in brief is as follows: bool runJobBless () { // check if already installed NSFileManager* filemgr = [NSFileManager defaultManager]; if ([filemgr fileExistsAtPath:@"/Library/PrivilegedHelperTools/com.company.Helper"] && [filemgr fileExistsAtPath:@"/Library/LaunchDaemons/com.company.Helper.plist"]) { // check helper version to match the client // ... return true; } // create authorization reference AuthorizationRef authRef; OSStatus status = AuthorizationCreate (NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authRef); if (status != errAuthorizationSuccess) return false; // obtain rights to install privileged helper AuthorizationItem authItem = { kSMRightBlessPrivilegedHelper, 0, NULL, 0 }; AuthorizationRights authRights = { 1, &authItem }; AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; status = AuthorizationCopyRights (authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL); if (status != errAuthorizationSuccess) return false; // SMJobBless does it all: verify helper against app and vice-versa, place and load embedded launchd.plist in /Library/LaunchDaemons, place executable in /Library/PrivilegedHelperTools CFErrorRef cfError; if (!SMJobBless (kSMDomainSystemLaunchd, (CFStringRef)@"com.company.Helper", authRef, &cfError)) { // check helper version to match the client // ... return true; } else { CFBridgingRelease (cfError); return false; } } void connectToHelper () { // connect to helper via XPC NSXPCConnection* c = [[NSXPCConnection alloc] initWithMachServiceName:@"com.company.Helper.mach" options:NSXPCConnectionPrivileged]; c.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol (SilentInstallHelperProtocol)]; [c resume]; // call function on helper and wait for completion dispatch_semaphore_t semaphore = dispatch_semaphore_create (0); [[c remoteObjectProxy] callFunction:^() { dispatch_semaphore_signal (semaphore); }]; dispatch_semaphore_wait (semaphore, dispatch_time (DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC)); dispatch_release (semaphore); [c invalidate]; [c release]; }
3
0
766
Oct ’25
Best practice for replacing deprecated sem_init/sem_wait in a cross-platform threading layer on macOS (arm64)
Hi all, I'm working on a cross-platform runtime that manages a pool of threads (think game engine / emulator style... dozens of guest threads mapped 1:1 to host pthreads). It was originally written for Linux and Windows and we're now porting to macOS on Apple Silicon. We've hit a wall with a deadlock on macOS and traced it back to our use of POSIX unnamed semaphores (sem_init / sem_wait / sem_post) for thread suspend and resume. We were unaware these have never actually been implemented on macOS, sem_init silently returns -1 with ENOSYS and then sem_wait just hangs forever. That explains our deadlock. The tricky part is how we use them. Our suspend mechanism works by sending SIGUSR1 to a target thread via pthread_kill. The signal handler then calls sem_wait to block the thread in place until another thread calls sem_post to resume it. So whatever we replace sem_init/sem_wait with needs to be safe to call from inside a signal handler. From what I can tell: dispatch_semaphore_wait is not documented as async-signal-safe pthread_cond_wait is also not async-signal-safe os_sync_wait_on_address looks promising but requires macOS 14.4+ which is a pretty high floor We could spin on a std::atomic with .wait() / .notify_all() but I've seen reports of high wake latency (up to 15ms) in libc++'s implementation on macOS My questions: What's the recommended way to block a thread inside a signal handler on macOS? Is there an async-signal-safe wait primitive I'm missing? Would restructuring to avoid blocking in the signal handler entirely be the better approach? For example, having the signal handler just set an atomic flag and then checking it at yield points — would that be the expected pattern on macOS? For the non-signal-handler suspend/resume paths, is dispatch_semaphore_t the right replacement for sem_t, or is there something better suited for high-frequency thread synchronization in 2026? Separately, we're also using ucontext (makecontext/swapcontext) for a fiber system on macOS and hitting issues on native arm64, it works under Rosetta but breaks natively. We have a setjmp/longjmp + manual stack pivot backend we can switch to. Is there any plan to fix or un-deprecate the ucontext functions on arm64, or should we just move off them permanently?
Replies
2
Boosts
0
Views
173
Activity
3w
SMAppService - helper is not started
My software installs a privileged daemon using the SMAppService api. After removing the executables and recompiling the software I sometimes find that it needs to be registered again. After doing this, i.e. ensuring the application is properly registered and enabled in Login Items & Extensions the helper is not run when initiated from XPC. SMAppService.status has returned .enabled, and there is a valid job dictionary for the helper. I check the job dictionary with a function called updatePenaltyBoxStatus() that was given to me by a friend but I think originated from Apple. If I logoff (or reboot), login again, manually open Login Items & Extensions to check registration, then retry the application, it works. I don't mind doing this but it is probably a bit much for a lot of my users. Is there a reliable way to do this programatically? Here is my Swift translation of updatePenaltyBoxStatus. I fetch the job dictionary with SMJobCopyDictionary() prior to calling isInPenaltyBox(). I also had to write C wrapper functions for the WIFEXITED and WIFEXITSTATUS macros. func isInPenaltyBox(_ dict: Dictionary<String, Any>?) -> Bool { guard let jobDict = dict else { // If the helper was in the penalty box, unregistering it doesn't change that. So don't override a previous helperInPenaltyBox value return m_penalty_box } if let lastExitStatusObj = jobDict["LastExitStatus"] as? NSNumber { let lastExitStatus = lastExitStatusObj.intValue if wifexited(Int32(lastExitStatus)) == 0 { // It might've stopped or exited due to a signal or whatever. // Regardless, it didn't meet our criteria for winding up in the penalty box. m_penalty_box = false } // Now get the exit status and check for `EX_CONFIG`. let status = wexitstatus(Int32(lastExitStatus)) let newInPenaltyBox = status == EX_CONFIG if m_penalty_box != newInPenaltyBox { Logger.instance.log( "Penalty box change: " + m_ident + " old: " + String(m_penalty_box) + " new: " + String(newInPenaltyBox)) } m_penalty_box = newInPenaltyBox } return m_penalty_box }
Replies
2
Boosts
0
Views
211
Activity
1w
App Terminated with 0x8BADF00D: Main Thread Blocked During Back-to-Back Messaging
Hello, I'm experiencing an issue with my app where it's being terminated by the system with a watchdog violation during back-to-back messaging operations. I've analyzed the crash logs but would appreciate additional insights on optimizing my approach. I'd appreciate any insights on how to resolve this problem. Crash Details: Exception Type: EXC_CRASH (SIGKILL) Termination Reason: FRONTBOARD with code 0x8BADF00D Error: "scene-update watchdog transgression: app exhausted real time allowance of 10.00 seconds" Reproduction Steps: User A initiates back-to-back messages to other User User A's UI becomes unresponsive and eventually the app crashes. Stack Trace Analysis: The crash occurs on the main thread, which appears to be blocked waiting for a condition in the keyboard handling system. The thread is stuck in [UIKeyboardTaskQueue _lockWhenReadyForMainThread] and related methods, suggesting an issue with keyboard-related operations during the messaging process. Crash Tag Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: FRONTBOARD 2343432205 <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-update watchdog transgression: app<com.msikodiak.eptt(AD934F8A-DF57-4B75-BE73-8CF1A9A8F856)>:301 exhausted real (wall clock) time allowance of 10.00 seconds ProcessVisibility: Foreground ProcessState: Running WatchdogEvent: scene-update WatchdogVisibility: Background WatchdogCPUStatistics: ( "Elapsed total CPU time (seconds): 6.390 (user 3.640, system 2.750), 11% CPU", "Elapsed application CPU time (seconds): 0.020, 0% CPU" ) ThermalInfo: ( "Thermal Level: 0", "Thermal State: nominal" ) reportType:CrashLog maxTerminationResistance:Interactive> Triggered by Thread: 0 Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 libsystem_kernel.dylib 0x1e773d438 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x2210bc328 _pthread_cond_wait + 1028 2 Foundation 0x1957d8a64 -[NSCondition waitUntilDate:] + 132 3 Foundation 0x1957d8888 -[NSConditionLock lockWhenCondition:beforeDate:] + 80 4 UIKitCore 0x1998f1238 -[UIKeyboardTaskQueue _lockWhenReadyForMainThread] + 456 5 UIKitCore 0x19a3d775c __59-[UIKeyboardImpl updateAutocorrectPrompt:executionContext:]_block_invoke_9 + 28 6 UIKitCore 0x19986b084 -[UIKeyboardTaskQueue lockWhenReadyForMainThread] + 168 7 UIKitCore 0x19a3f2994 -[UIKeyboardTaskQueue waitUntilTaskIsFinished:] + 148 8 UIKitCore 0x19a3f2ac4 -[UIKeyboardTaskQueue performSingleTask:breadcrumb:] + 132 9 UIKitCore 0x199e2f7e4 -[_UIKeyboardStateManager updateForChangedSelection] + 144 10 UIKitCore 0x199e24200 -[_UIKeyboardStateManager invalidateTextEntryContextForTextInput:] + 92 11 WebKit 0x1ad52fa54 WebKit::PageClientImpl::didProgrammaticallyClearFocusedElement(WebCore::ElementContext&&) + 40 12 WebKit 0x1ad55adcc WebKit::WebPageProxy::didProgrammaticallyClearFocusedElement(WebCore::ElementContext&&) + 136 13 WebKit 0x1acec74e8 WebKit::WebPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 18604 14 WebKit 0x1acd21184 IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 236 15 WebKit 0x1ace449b8 WebKit::WebProcessProxy::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 40 16 WebKit 0x1ace44228 WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 1764 17 WebKit 0x1acd1e904 IPC::Connection::dispatchMessage(WTF::UniqueRef<IPC::Decoder>) + 268 18 WebKit 0x1acd1e478 IPC::Connection::dispatchIncomingMessages() + 576 19 JavaScriptCore 0x1ae386b8c WTF::RunLoop::performWork() + 524 20 JavaScriptCore 0x1ae386960 WTF::RunLoop::performWork(void*) + 36 21 CoreFoundation 0x196badce4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 22 CoreFoundation 0x196badc78 __CFRunLoopDoSource0 + 172 23 CoreFoundation 0x196bac9fc __CFRunLoopDoSources0 + 232 24 CoreFoundation 0x196babc3c __CFRunLoopRun + 840 25 CoreFoundation 0x196bd0700 CFRunLoopRunSpecific + 572 26 GraphicsServices 0x1e3711190 GSEventRunModal + 168 27 UIKitCore 0x1997ee240 -[UIApplication _run] + 816 28 UIKitCore 0x1997ec470 UIApplicationMain + 336 29 Telstra PTT 0x1004d30c8 main + 56 30 dyld 0x1bd5d3ad8 start + 5964
Replies
4
Boosts
1
Views
435
Activity
Oct ’25
Does BGAppRefreshTask require an internet connection?
Basically the title. I am trying to implement a local notification to trigger, regardless of internet connection, around 3-5pm if a certain array in the app is not empty to get the user to sync unsaved work with the cloud. I wanted to used the BGAppRefreshTask as I saw it was lightweight and quick for just posting a banner notification but after inspecting it in the console, it looks like it needs internet connection to trigger. Is this the case or am I doing something wrong? Should I be using the BGProcessingTask instead?
Replies
1
Boosts
0
Views
139
Activity
Jul ’25
[iOS 26 Beta] BGTaskScheduler.supportedResources incorrectly reports no GPU support for BGContinuedProcessingTask on capable hardware
Testing Environment: iOS: 26.0 Beta 7 Xcode: Beta 6 Description: We are implementing the new BGContinuedProcessingTask API introduced in iOS 26. We have followed the official documentation and WWDC session guidance to configure our project. The Background Modes (processing) and Background GPU Access capabilities have been added in Xcode. The com.apple.developer.background-tasks.continued-processing.gpu entitlement is present and set to in the .entitlements file. The provisioning profile details viewed within Xcode explicitly show that the "Background GPU Access" capability and the corresponding entitlement are included. Despite this correct configuration, when running the app on supported hardware (iPhone 16 Pro), a call to BGTaskScheduler.supportedResources.contains(.gpu) consistently returns false. This prevents us from setting request.requiredResources = .gpu. As a result, when the BGContinuedProcessingTask starts without the GPU resource flag, our internal Metal-based exporter attempts to access the GPU and is terminated by the system, throwing an IOGPUMetalError: Insufficient Permission (to submit GPU work from background). We have performed extensive debugging, including a full reset of the provisioning profile (removing/re-adding capabilities, toggling automatic signing, cleaning build folders, and reinstalling the app), but the issue persists. This strongly suggests a bug in the iOS 26 beta where the runtime is failing to correctly validate a valid entitlement. Additionally, we've observed inconsistent behavior across devices. On an A16-based iPad, the task submits successfully (BGTaskScheduler.submit does not throw an error), but the launch handler is never invoked by the system. On the iPhone 16 Pro, the handler is invoked, but we encounter the supportedResources issue described above. This leads us to ask for clarification on the exact hardware requirements for this feature. We hypothesize that it may be limited to devices that support Apple Intelligence (A17 Pro and newer). Could you please confirm this and provide official documentation on the device support criteria? Steps to Reproduce: Create a new Xcode project. In Signing & Capabilities, add "Background Modes" (with "Background processing" checked) and "Background GPU Access". Add a permitted identifier (e.g., "com.company.test.*") to BGTaskSchedulerPermittedIdentifiers in Info.plist. In application(_:didFinishLaunchingWithOptions:) or a ViewController's viewDidLoad, log the result of BGTaskScheduler.shared.supportedResources.contains(.gpu). Build and run on a physical, supported device (e.g., iPhone 16 Pro). Expected Results: The log should indicate that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns true. Actual Results: The log shows that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns false.
Replies
6
Boosts
0
Views
888
Activity
Dec ’25
Stay connected to Medical BLE device in background
I work for a large medical device company. We have a 1st party BLE enabled medical device that must be very battery efficient. To this end, if a connection is lost, the BLE radio is powered down after 60 seconds and will only turn back on when a physical button on the device is pressed. I've been tasked with connecting to the device, staying connected to the device, and being able to retrieve data from the device upon a timed action. For instance, this could include a data read and transmission while they sleep. The key part of this is staying reliably connected for extended periods of time. This is a BYOD setup, and we cannot control power profiles. I would very much appreciate any information, recommendations, and/or insights into solving this problem. Thanks!
Replies
1
Boosts
0
Views
513
Activity
Sep ’25
How to detect or opt out of iOS app prewarming?
Hi, We are running into issues with iOS app prewarming, where the system launches our app before the user has entered their passcode. In our case, the app stores flags, counters, and session data in UserDefaults and the Keychain. During prewarm launches: UserDefaults only returns default values (nil, 0, false). We have no way of knowing whether this information is valid or just a placeholder caused by prewarming. Keychain items with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly are inaccessible, which can lead to broken business logic (the app can assume no session exists). No special launch options or environment variables appear to be set. We can reproduce this 100% of the time by starting a Live Activity in the app before reboot. Here’s an example of the workaround we tried, following older recommendations: __attribute__((constructor)) static void ModuleInitializer(void) { char* isPrewarm = getenv("ActivePrewarm"); if (isPrewarm != NULL && isPrewarm[0] == '1') { exit(0); // prevent prewarm launch from proceeding } } On iOS 16+, the ActivePrewarm environment variable doesn’t seem to exist anymore (though older docs and SDKs such as Sentry reference it). We also tried listening for UIApplication.protectedDataDidBecomeAvailableNotification, but this is not specific to prewarming (it also fires when the device gets unlocked) and can cause watchdog termination if we delay work too long. Questions: Is there a supported way to opt out of app prewarming? What is the correct way to detect when an app is being prewarmed? Is the ActivePrewarm environment variable still supported in iOS 16+? Ideally, the UserDefaults API itself should indicate whether it is returning valid stored values or defaults due to the app being launched in a prewarm session. We understand opting out may impact performance, but data security and integrity are our priority. Any guidance would be greatly appreciated.
Replies
1
Boosts
0
Views
244
Activity
Oct ’25
SSO Extension Fails XPC Connection to System Daemon (mach-lookup exception used)
Hello, I'm running into an issue with a complex macOS application (non-AppStore) structure involving an unsandboxed system daemon and a sandboxed SSO Extension attempting to communicate via XPC Mach service. The macOS app is composed of three main components: Main App: unsandboxed, standard macOS application. System Daemon: unsandboxed executable installed with a .plist to /Library/LaunchDaemons/ and loaded by launchd. It exposes an XPC Mach Service. SSO Extension: a sandboxed Authentication Services Extension (ASAuthorizationProviderExtension). Main App to System Daemon communication works perfectly. The unsandboxed main app can successfully create and use an XPC connection to the System Daemon's Mach service. But SSO Extension cannot establish an XPC connection to the System Daemon's Mach service, despite using the recommended temporary exception entitlement. I have added the following entitlement to the SSO Extension's entitlements file: <key>com.apple.security.temporary-exception.mach-lookup.global-name</key> <array> <string>my.xpc.service.system.daemon</string> </array> (The name my.xpc.service.system.daemon is the exact name registered by the System Daemon in its Launch Daemon plist's MachServices dictionary.) When the SSO Extension attempts to create the connection, the following log output is generated: default 08:11:58.531567-0700 SSOExtension [0x13f19b090] activating connection: mach=true listener=false peer=false name=my.xpc.service.system.daemon default 08:11:58.532150-0700 smd [0xb100d8140] activating connection: mach=false listener=false peer=true name=com.apple.xpc.smd.peer[1575].0xb100d8140 error 08:11:58.532613-0700 smd Item real path failed. Maybe the item has been deleted? error 08:11:58.532711-0700 SSOExtension Unable to find service status () error: 22 The error Unable to find service status () error: 22. Error code 22 typically translates to EINVAL (Invalid argument), but in this context, it seems related to the system's ability to find and activate the service for the sandboxed process. Questions: Is the com.apple.security.temporary-exception.mach-lookup.global-name entitlement sufficient for a sandboxed SSO Extension to look up a system-wide Launch Daemon Mach service, or are there additional restrictions or required entitlements for extensions? The smd log output Item real path failed. Maybe the item has been deleted? seems concerning. Since the unsandboxed main app can connect, this suggests the service is running and registered. Could this error indicate a sandbox permission issue preventing smd from verifying the path for the sandboxed process? Are there specific sandboxing requirements for Mach service names when communicating from an Extension versus a main application? Any guidance on how a sandboxed SSO Extension can reliably connect to an unsandboxed, non-app-group-related system daemon via XPC Mach service would be greatly appreciated!
Replies
2
Boosts
0
Views
289
Activity
Oct ’25
Recursively walk a directory using File Coordination
What’s the recommended way to recursively walk through a directory tree using File Coordination? From what I understand, coordinating a read of a directory only performs a “shallow” lock; this would mean that I’d need to implement the recursive walk myself rather than use FileManager.enumerator(at:includingPropertiesForKeys:options:errorHandler:) plus a single NSFileCoordinator.coordinate(with:queue:byAccessor:) call. I’m trying to extract information from all files of a particular type, so I think using NSFileCoordinator.ReadingOptions.immediatelyAvailableMetadataOnly on each file before acquiring a full read lock on it (if it’s the right file type) would make sense. Am I on the right track?
Replies
5
Boosts
0
Views
180
Activity
Oct ’25
What is the new name of the OSDUIHelper process on macOS Tahoe?
I am currently developing a macOS app that can show system HUDs in the Notch Till Sequoia I used to kill the OSDUIHelper process (which displays the default macOS Volume and Brightness control HUDs) - and replaced it with my app's HUDs But, it is not working on macOS Tahoe anymore as the OSDUIHelper process is no longer there due to the UI changes Has the process been renamed - or is there any other way to kill the process?
Replies
1
Boosts
0
Views
180
Activity
Oct ’25
Bluetooth work with BGTaskScheduler
Hi All, I'm working on an app that needs to connect to BLE device and on defined schedules download data from the device. the amount of data is segnificant and might take around a minute to download. we tought about utilizing both state restoration and preservation for app waking and scheduling (triggered by the ble peripheral) and BGTaskScheduler to schedule a task that will handle a long running task to manage the full data download. now, will this solution in general valid? isnt it a "hack" that goes around the 10s limit that state restoration enforces? i know there are limitations for BGTask (like when it runs, it might be terminated by the system etc) but considering that, can we proceed with this approach without breaching apple guidelines? thank you in advance!
Replies
2
Boosts
0
Views
232
Activity
Oct ’25
Does Mac Catalyst support Background Processing?
I have an app for macOS that is built using Mac Catalyst. I need to perform some background processing. I'm using BGProcessingTaskRequest to schedule the request. I have also integrated CKSyncEngine so I need that to be able to perform its normal background processing. On iOS, when the user leaves the app, I can see a log message that the request was scheduled and a bit later I see log messages coming from the actual background task code. On macOS I ran the app from Xcode. I then quit the app (Cmd-q). I can see the log message that the request was scheduled. But the actual task is never run. In my test, I ran my app on a MacBook Pro running macOS 26.0. When I quit the app, I checked the log file in the app sandbox and saw the message that the task was scheduled. About 20 minutes later I closed the lid on the MacBook Pro for the night. I did not power down, it just went to sleep. Roughly 10 hours later I opened the lid on the MacBook Pro, logged in, and checked the log file. It had not been updated since quitting the app. I should also mention that the laptop was not plugged in at all during this period. My question is, does a Mac Catalyst app support background processing after the user quits the app? If so, how is it enabled? The documentation for BGProcessingTaskRequest and BGProcessingTask show they are supported under Mac Catalyst, but I couldn't find any documentation in the Background Tasks section that mentioned anything specific to setup for Mac Catalyst. Running the Settings app and going to General -> Login Items & Extension, I do not see my app under the App Background Activity section. Does it need to be listed there? If so, what steps are needed to get it there? If this is all documented somewhere, I'd appreciate a link since I was not able to find anything specific to making this work under Mac Catalyst.
Replies
4
Boosts
1
Views
313
Activity
Nov ’25
Which thread is the main thread?
As far as I understand, the main thread has a run loop. When an iOS app launches, the process must keep the run loop running to stay alive. Does that mean the main thread is the very first thread created when the process starts?
Replies
1
Boosts
0
Views
120
Activity
Nov ’25
NotificationCenter.notifications(named:) appears to buffer internally and can drop notifications, but is this documented anywhere?
I've experimentally seen that the notifications(named:) API of NotificationCenter appears to buffer observed notifications internally. In local testing it appears to be limited to 8 messages. I've been unable to find any documentation of this fact, and the behavior seems like it could lead to software bugs if code is not expecting notifications to potentially be dropped. Is this behavior expected and documented somewhere? Here is a sample program demonstrating the behavioral difference between the Combine and AsyncSequence-based notification observations: @Test nonisolated func testNotificationRace() async throws { let testName = Notification.Name("TestNotification") let notificationCount = 100 var observedAsyncIDs = [Int]() var observedCombineIDs = [Int]() let subscribe = Task { @MainActor in print("setting up observer...") let token = NotificationCenter.default.publisher(for: testName) .sink { value in let id = value.userInfo?["id"] as! Int observedCombineIDs.append(id) print("🚜 observed note with id: \(id)") } defer { extendLifetime(token) } for await note in NotificationCenter.default.notifications(named: testName) { let id: Int = note.userInfo?["id"] as! Int print("🚰 observed note with id: \(id)") observedAsyncIDs.append(id) if id == notificationCount { break } } } let post = Task { @MainActor in for i in 1...notificationCount { NotificationCenter.default.post( name: testName, object: nil, userInfo: ["id": i] ) } } _ = await (post.value, subscribe.value) #expect(observedAsyncIDs.count == notificationCount) // 🛑 Expectation failed: (observedAsyncIDs.count → 8) == (notificationCount → 100) #expect(observedCombineIDs == Array(1...notificationCount)) print("done") }
Replies
2
Boosts
0
Views
311
Activity
Dec ’25
ExtensionFoundation/ExtensionKit across app boundary
Hi there, I'm trying to work on an architecture where one app exposes an API (Extension Host) that other apps can plugin to. I've been reading all I can from the docs and whatever I can find online. It seemed like iOS26 added the ability to do such a thing (at least in early builds). Is that the case? Has the functionality been walked back such that extensions can only be loaded in iOS from within the single app bundle? My use case is the following: I'm working on an agent app that desires to have 3rd party developers add functionality (think how MCP servers add functionality to LLMs). The 3rd party plugins would be provided in their own app bundles vetted by the AppStore review team, of course, and would only provide hooks, basically, the main app can use to execute functions or get state. This is the best thread I found on the topic, and the subtext is that it needs to be in the same bundle. https://developer.apple.com/forums/thread/803896?answerId=865314022#865314022 Let's say for the moment that this isn't possible using ExtensionKit. What's the best way to achieve this? Our current best alternative idea is a hidded WebKit window that runs JS/WASM but that's so hackish. Please let me know, thanks!
Replies
3
Boosts
0
Views
276
Activity
Dec ’25
Background upload issue in WatchOS
We are developing a watchOS application that records long audio sessions and uploads them to our backend in chunks (~5 MB each) using pre-signed URLs and URLSession background upload. Current behavior: While audio recording is active, uploads continue successfully even when the app is in the background. Once the recording stops, if multiple chunks (e.g., 10+) are still pending, the remaining uploads do not proceed in the background and appear to be suspended. We attempted to use WKExtendedRuntimeSession (mindfulness type) to allow sufficient time to enqueue background upload tasks, but the session is invalidated when the app goes to the background (e.g., wrist down or app inactive), which prevents reliable scheduling of uploads. Additionally, we added the entitlement: com.apple.developer.extended-runtime-session (mindfulness) in the Watch app entitlements file, but Xcode automatic signing fails with: “Provisioning profile does not include the com.apple.developer.extended-runtime-session entitlement.” It appears that the provisioning profile is not being updated to include this entitlement. Our questions: Is WKExtendedRuntimeSession (mindfulness) expected to support scheduling background URLSession uploads after the app goes to background? How should we reliably complete pending background uploads on watchOS after a long recording session ends? Is there any additional entitlement or recommended approach for this use case? Why is the extended runtime entitlement not being applied to the provisioning profile despite being added in the entitlements file? We are aiming to follow Apple-recommended practices for long-running tasks and background uploads on watchOS. Any guidance would be greatly appreciated.
Replies
2
Boosts
0
Views
351
Activity
Mar ’26
iOS: Issues getting beginBackgroundTaskWithName working reliably
We have tried using background tasks for file saving via (UIBackgroundTaskIdentifier) beginBackgroundTaskWithName:(NSString *) taskName expirationHandler:(void (^)(void)) handler; when our app goes into the background and/or is closed by the user. But we cannot make it work the way the documentation tells us it should. While task creation never reports an issue (in fact it never calls our expiration handler at all) and the returned task id is always valid, when we ask for how much time we have left via backgroundTimeRemaining we always get 6s instead of the specified 30s. We tried to create the task when the app state goes to inactive or when our delegate is called via applicationDidEnterBackground but it makes no difference, besides the fact that the remaining time reported is basically max double, when the app is not in background yet which is by design as far we understand. But we don't even get the 6s for saving when a user closes the app. Because almost immediately after applicationDidEnterBackground our delegate is called via applicationWillTerminate which will then again almost immediately end in the app receiving a SIGKILL. So we must be doing something wrong. Why would applicationWillTerminate be called at all when we have a valid background task that reports we have 6s left? We tried blocking the thread in both background and terminate to at least give us the 5s the spec says we have before we get the SIGKILL. That works in general but doesn't feel like the correct approach and we do need more time than the 5s or 6s we get this way. Are we supposed to add something to our plist in order for these background tasks to work correctly? It is very confusing that there is a second mechanism that's also called background tasks for running apps in the background in general, which is not applicable to us. Are we supposed to block somewhere when we create the task? Or even spin up an extra thread for the task? Why is our expirationHandler never called? The spec says that our handler should be called if it was unable to "grant the ask assertion" so it seems like we do not have that problem. But it's also supposed to be called just before we are running out of time but by that time the app is already dead. This was all tested on iOS 26.3 and it is probably worth mentioning that our app is Qt-based.
Replies
4
Boosts
0
Views
216
Activity
4w
applicationWillTerminate to wrap up Background Recording
Hello together, the user is able to do recordings with my app. The recordings also runs, while the App is in Background. I have Background Modes Audio & Background enabled. When the user accidentally terminates the App while the recording is still running, the whole recording is lost. I tried AppDelegate applicationWillTerminate on my iOS 26 App and it works perfectly to wrap up the LiveActivity that is shown while the recording is active. But it does not save the Audio and also doesn't update the Widgets (they are interactive and show a different state while recording and stay stuck in recording-state on accidental termination). Any ideas? Best wishes, Dominik
Replies
2
Boosts
0
Views
148
Activity
1w
Privileged helper without SMJobBless
To establish a privileged helper daemon from a command line app to handle actions requiring root privileges I still use the old way of SMJobBless. But this is deprecated since OSX 10.13 and I want to finally update it to the new way using SMAppService. As I'm concerned with securing it against malicious exploits, do you have a recommended up-to-date implementation in Objective-C establishing a privileged helper and verifying it is only used by my signed app? I've seen the suggestion in the documentation to use SMAppService, but couldn't find a good implementation covering security aspects. My old implementation in brief is as follows: bool runJobBless () { // check if already installed NSFileManager* filemgr = [NSFileManager defaultManager]; if ([filemgr fileExistsAtPath:@"/Library/PrivilegedHelperTools/com.company.Helper"] && [filemgr fileExistsAtPath:@"/Library/LaunchDaemons/com.company.Helper.plist"]) { // check helper version to match the client // ... return true; } // create authorization reference AuthorizationRef authRef; OSStatus status = AuthorizationCreate (NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authRef); if (status != errAuthorizationSuccess) return false; // obtain rights to install privileged helper AuthorizationItem authItem = { kSMRightBlessPrivilegedHelper, 0, NULL, 0 }; AuthorizationRights authRights = { 1, &authItem }; AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; status = AuthorizationCopyRights (authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL); if (status != errAuthorizationSuccess) return false; // SMJobBless does it all: verify helper against app and vice-versa, place and load embedded launchd.plist in /Library/LaunchDaemons, place executable in /Library/PrivilegedHelperTools CFErrorRef cfError; if (!SMJobBless (kSMDomainSystemLaunchd, (CFStringRef)@"com.company.Helper", authRef, &cfError)) { // check helper version to match the client // ... return true; } else { CFBridgingRelease (cfError); return false; } } void connectToHelper () { // connect to helper via XPC NSXPCConnection* c = [[NSXPCConnection alloc] initWithMachServiceName:@"com.company.Helper.mach" options:NSXPCConnectionPrivileged]; c.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol (SilentInstallHelperProtocol)]; [c resume]; // call function on helper and wait for completion dispatch_semaphore_t semaphore = dispatch_semaphore_create (0); [[c remoteObjectProxy] callFunction:^() { dispatch_semaphore_signal (semaphore); }]; dispatch_semaphore_wait (semaphore, dispatch_time (DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC)); dispatch_release (semaphore); [c invalidate]; [c release]; }
Replies
3
Boosts
0
Views
766
Activity
Oct ’25
BGContinuedProcessingTask GPU Access
We added the com.apple.developer.background-tasks.continued-processing.gpu key to the entitlement file and set it to true, but BGTaskScheduler.supportedResources does not include gpu. How can we configure it to obtain permission for GPU access in the background? Test device: iPhone 16 Pro Max, iOS 26 release version.
Replies
2
Boosts
1
Views
352
Activity
Sep ’25