I have been fighting this problem for two months and would love any help, advice or tips. Should I file a DTS ticket?
Summary
We attach a JPEG image to a local notification using UNNotificationAttachment. iOS reports the delivered notification as having attachments=1, but intermittently no image preview appears in Notification Center. In correlated cases, the attachment’s UNNotificationAttachment.url (which points into iOS’s attachment store) becomes unreadable (Data(contentsOf:) fails) even though the delivered notification still reports attachments=1.
This document describes the investigation, evidence, and mitigations attempted.
Product / Component
- UserNotifications framework
UNNotificationAttachmentrendering in Notification UI (Notification Center / banner / expanded preview)
Environment
- App: OnThisDay (SwiftUI, Swift 6)
- Notifications: local notifications scheduled with
UNCalendarNotificationTrigger(repeats: false) - Attachment: JPEG generated from PhotoKit (
PHImageManager.requestImage) and written to app temp directory, then passed intoUNNotificationAttachment. - Test contexts:
- Debug builds (direct Xcode install)
- TestFlight builds (production signing)
- iOS devices: multiple, reproducible with long runs and user clearing delivered notifications
Expected Result
- Delivered notifications with
UNNotificationAttachmentshould consistently show the image preview in Notification Center (thumbnail and expanded preview), as long as the notification reportsattachments=1. - If the OS reports
attachments=1, the attachment’s store URL should remain valid/readable for the lifetime of the delivered notification still present in Notification Center.
Actual Result
Intermittently:
- Notification Center shows no image preview even though the app scheduled the notification with an attachment and iOS reports the delivered notification as having
attachments=1. - When we inspect delivered notifications via
UNUserNotificationCenter.getDeliveredNotifications, the delivered notification’srequest.content.attachments.first?.urlexists but is unreadable (attemptingData(contentsOf:)returns nil / throws), i.e. the backing attachment-store file appears missing or inaccessible.
In some scenarios the attachment-store file is readable for hours while the notification is pending, and then becomes unreadable after the notification is delivered.
Reproduction Scenarios (Observed)
Next-day reminders show attachment-store unreadable after delivery
1. Schedule a one-shot daily reminder for next day (07:00 local time) with UNCalendarNotificationTrigger(repeats: false) and a JPEG attachment.
2. During the prior day, periodic background refresh tasks verify the pending notification’s attachment-store URL is readable (pendingReadable=true).
3. After the reminder is delivered the next morning, the delivered snapshot shows the delivered notification’s attachment-store URL is unreadable (readable=false) and Notification Center shows no preview.
Interpretation: the attachment-store blob appears to become inaccessible around/after delivery, despite being readable while pending.
Evidence and Instrumentation
We added non-crashing diagnostic logging (Debug builds) around:
Scheduling time
- Logged that we successfully created a
UNNotificationAttachmentfrom a unique temp file. - Logged that
UNUserNotificationCenter.add(request)succeeded. - Queried
pendingNotificationRequests()and logged the scheduled request’s attachmenturl.lastPathComponent(iOS attachment-store filename).
Delivered time (when app becomes active)
- Called
UNUserNotificationCenter.getDeliveredNotificationsand logged:- delivered count, attachment count
- attachment
url.lastPathComponent - whether
Data(contentsOf: attachment.url)succeeds (readable=true/false)
Content fingerprinting
- Fingerprinted the exact JPEG bytes we wrote (SHA-256 prefix + byte count).
- Logged the iOS attachment-store filename (
url.lastPathComponent) returned post-scheduling.
Decode validation probe (later addition)
- When
Data(contentsOf:)succeeds, we validate it decodes as an image usingCGImageSourceCreateWithDataand log:- UTI (e.g.
public.jpeg) - pixel width/height
- magic header bytes
- UTI (e.g.
What we tried / Mitigations
Proactive “self-heal” for pending notifications
Change: during background refresh/foreground refresh, verify the pending daily reminder’s attachment-store URL readability. If it’s unreadable, reschedule with a new attachment (same trigger).
Rationale: if iOS drops the store file before delivery, recreating could repair it.
Result: We observed cases where pending remained readable but delivered became unreadable after delivery, so this doesn’t address all observed failures. It is still valuable hardening.
Increase scheduling frequency / reschedule closer to fire time (proposed/considered)
We discussed adding a debug mode to always recreate the daily reminder during background refresh tasks (or only within N hours of fire time) to reduce the time window between attachment creation and delivery.
Status: experimental; not yet confirmed to resolve the “pendingReadable=true → delivered unreadable after delivery” failure.
Impact
- The primary UX value of the daily reminder is the preview photo; missing previews degrade core functionality.
- Failures are intermittent and appear dependent on OS attachment-store behavior and Notification Center actions (clearing notifications), making them difficult to mitigate fully app-side.
Notes / Questions for Apple
1. Is iOS allowed to coalesce/deduplicate UNNotificationAttachment storage across notifications? If so, what is the retention model when delivered notifications are removed?
2. If a delivered notification still reports attachments=1, should its attachment-store URL remain valid/readable while the notification is still present in Notification Center?
3. In “next-day” one-shot scheduling scenarios, can the attachment-store blob be purged between scheduling and delivery (or immediately after delivery) even if the notification remains visible?
4. Is there a recommended pattern to ensure attachment previews remain stable for long-lived scheduled notifications (hours to a day), especially when using UNCalendarNotificationTrigger(repeats: false)?
Minimal Code Pattern (simplified)
1. Generate JPEG (PhotoKit → UIImage → JPEG Data).
2. Write to a unique temp URL.
3. Create attachment:
UNNotificationAttachment(identifier: <uuid>, url: <tempURL>, options: [UNNotificationAttachmentOptionsTypeHintKey: "public.jpeg"])
4. Schedule notification with a calendar trigger for the next morning.