WidgetKit memory issues only in iOS 18.3

I've been working on a new application and beta testing with TestFlight. When iOS 18.3 came out, my widgets stopped working due to using too much memory. I've been trying to debug for a while now, but not making much progress. Now that iOS 18.4 is out, I noticed the widgets are working again.

I'm wondering if there was some change made in iOS 18.3 that was rolled back in iOS 18.4 that I'm not seeing in the iOS Release Notes etc? I haven't seen much in the Developer Forums, either.

My concern is that perhaps Apple decided to make the 30MB Widget memory limit a "hard" limit, but then rolled it back, perhaps temporarily, so I'd like some clarity on the situation if possible.

Otherwise, I did notice that it seemed as if all of my widgets were loaded at once, even if only one widget was installed, this boosting the memory usage significantly. If so, that might indicate that a bug was fixed in the Widget Provider system?

In any case, I'd appreciate any information or advice on this.

Thanks!

Hi,

For WidgetKit there are a few things to consider:

You get 10MB of space per timeline. You get 72 refreshes per day and an unlimited amount of entries. This means you can create a timeline of size 10MB and refresh every 20 minutes.

The system, or Springboard essentially, will reload if resources are available to do such. None of this is guaranteed. OnAppear isn't really valid for Widgets because they don't explicitly have a lifecycle and UI should be driven by your entry values, not runtime updates when the UI appears. The views themselves are archived and saved as a timeline so even in onAppear things aren't editable.

Lastly, if you think there is an issue with reloading, the best first course of action would be to use Console.app to monitor to the relevant processes related to your app and extensions.

A good way to start would be with filtering by the BundleID of the target and / or the target name itself (the process name). To debug WidgetKit, LiveActivities, Dynamic Island you'll want to monitor springboardd, liveactivitiesd along with other relevant processes.

Ok, I've been able to narrow down the issue and I have a workaround.

I'd love to have more detail about the changes that necessitated this in iOS 18.3, but seem to have been reverted in iOS 18.4. 

The main fix is adding a new WidgetImage function which downsizes an image like so:

func WidgetImage(_ name: String, size: CGFloat) -> Image {
    guard let uiImage = UIImage(named: name) else {
        Logger.error("WidgetImage missing \(name)")
        return Image(systemName: "exclamationmark.triangle")
    }
    let thumbnailSize = CGSize(width: size, height: size)
    guard let thumbnail = uiImage.preparingThumbnail(of: thumbnailSize) else {
        Logger.error("WidgetImage thumbnail error \(name)")
        return Image(systemName: "exclamationmark.triangle")
    }
    return Image(uiImage: thumbnail)
}

Usage example, where previously we would have:

Image(icon)
    .resizable()
    .widgetAccentedRenderingMode(.accented)
    .scaledToFit()
    .frame(width: 58.0, height: 58.0)

...we update to use WidgetImage:

WidgetImage(icon, size: 58.0)
    .resizable()
    .widgetAccentedRenderingMode(.accented)
    .scaledToFit()
    .frame(width: 58.0, height: 58.0)

Please let me know if there's a better way to handle this, or any other suggestions.

Note that we did downsize our images to the 58x58 size, but even resizing them down to 20x20 as we use in some places causes issues.

Note also that this workaround fails for images with different light/dark appearance modes. For those cases, we continue using Image() and try to keep the images as small as possible to stay under the memory limit.

Thanks!

It is better to not try and resize images in your extension process since the entire process is memory constrained.

WidgetKit memory issues only in iOS 18.3
 
 
Q