Hi There, My app is a legacy project built with Objective C. The host app shared data with the service extension by using
NSUserDefaults *userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.myapp.project"];
and it worked until a customer recently reported a bug (iOS 18.6). After debugging, I found that data sharing from the host app to the service extension was not working correctly.
The host app updated a field's value, but the service still used the old or stale value, causing the issue.
HostApp saved info
2026-06-01 13:44:07.020 [INFO] (VMP)(ThreadID: 0x10a85c000): "Saved Vomo information {
"EXT_AP_IP" = 1c28af0f9d73;
"EXT_PING_DND" = 0;
"EXT_PING_USER_NAME" = aaa08AA541F8;
"EXT_SERIAL_ACK_TIME" = "2026-06-01 20:44:07 +0000";
"EXT_SERIAL_NO" = 689;
"EXT_SERVER_NAME" = "10.xxx.xxx.182";
"EXT_VOICE_LOGIN" = 1;
}"
Service extension read value:
2026-06-01 13:46:09.678 [INFO] (VMP) - (EXTENSION)(ThreadID: 0x1050a41d0): "start Vomo with Server: [10.xxx.xxx.79] and userName [aaa08AA541F8]"
I can see the value shared from host app is:
10.xxx.xxx.182, but service extension still took the stale value 10.xxx.xxx.79
First I thought it is synchronized issue, however, apple deprecated those API,
CFPreferencesAppSynchronize((__bridge CFStringRef)@"group.com.myexample.project");
How to ensure the shared value successfully delivered to service extension?
Thanks.
yes for now
OK.
If this were something that was commonly reproducible then it might be worthwhile digging deeper into the user defaults subsystem to work out why it’s failing. However, the fact that only one person is seeing it presents you with a choice:
- You can stick with user defaults and try to help that one specific person.
- You can move off user defaults.
If I were in your shoes I’d probably do the latter. As I mentioned above, user defaults is best suited for user preferences, as oppose to stuff that’s critical for your app.
Switching to a file might not be trivial depending on the specifics of your app:
- It’s best if you can set things up so that only your main app writes the file and your app extensions read it. That way you don’t have worry about merge conflicts.
- Write a file of preferences is remarkably easy: Historically you’d just call
-[NSDictionary writeToURL:atomically:]. That’s deprecated, but you can achieve the same result by serialising a property list dictionary to data and writing that using-[NSData writeToURL:options:error:]. - Make sure you use an atomic writing mechanism. Without that, the reader might see inconsistent state.
- It’s easiest if you don’t cache the file’s state in the app extension. That way you don’t have to worry about cache invalidation.
- But if you must cache the file’s state, you can use a Darwin notification to flush that cache.
- Make sure the file’s data protection is appropriate for all the app extensions that read it.
If things are more complex than this — for example, if you need to write to the file from multiple processes — then lemme know and we can talk about more complex options. However, in common cases the approach above is both simple and effective.
And please do reply back here if you have follow-up questions about any of this.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"