'WidgetKit not work for an Intent Handler to Provide Dynamic Values

I am trying to implement a widget where the user can choose a city dynamically via an intent.

I followed the step by step guide provided by apple here: https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget

I think I have done everything correctly but the result I have is always this:

enter image description here

I can see the list of cities but when I select one the screen goes black, as seen in the video and the debug crashes. Both on simulator and device.

My goal is to have the city selected within the widget's getTimeline

Here is the code I use:

IntentHandler.swift in SiriIntent's target:

import Intents

class IntentHandler: INExtension, DynamicCitySelectionIntentHandling {
    func provideCity_paramOptionsCollection(for intent: DynamicCitySelectionIntent, with completion: @escaping (INObjectCollection<City>?, Error?) -> Void) {
        let dataSource = PersistenceController.shared.getAllForecastDataCoreData()
        
        let coreDataCities: [City] = dataSource.map { cityCoreData in
            let city = City(identifier: "\(cityCoreData.cityID ?? -1)", display: cityCoreData.cityName ?? "")
            return city
        }
        
        let collection = INObjectCollection(items: coreDataCities)

        completion(collection, nil)
    }
    
    override func handler(for intent: INIntent) -> Any {
        return self
    }
}

Part of code in Widget class:

import WidgetKit
import SwiftUI
import Combine
import MapKit

typealias Entry = ForecastEntry

struct Provider: IntentTimelineProvider {
    
    let snapshotEntry = Entry(date: Date(), forecastViewModel: .initForPlaceholder())
    
    func placeholder(in context: Context) -> ForecastEntry {
        snapshotEntry
    }
    
    public func getSnapshot(
      for configuration: DynamicCitySelectionIntent,
      in context: Context,
      completion: @escaping (Entry) -> Void
    ) {
        let entry = snapshotEntry
        completion(entry)
    }
    
    public func getTimeline(
      for configuration: DynamicCitySelectionIntent,
      in context: Context,
      completion: @escaping (Timeline<Entry>) -> Void
    ) {
        
        let currentDate = Date()
        let correctDate = Calendar.current.date(byAdding: .second, value: 150, to: currentDate)
        WidgetServiceManager.shared.fetchWeather(forCityId: configuration.city_param?.identifier ?? "") { data in
            guard let _data = data else { return }
            let entry = Entry(date: currentDate,
                              forecastViewModel: ForecastCardViewModel(weatherModel: _data,
                                                                       isForUserPosition: false))
            let timeline = Timeline(entries: [entry],
                                    policy: .after(correctDate ?? Date()))
            completion(timeline)
        }
    }
}

@main
struct WeatherAppWidget: Widget {
    let kind: String = "WeatherAppWidget"
    
    init() {
    }
    
    var body: some WidgetConfiguration {
        IntentConfiguration(
          kind: kind,
          intent: DynamicCitySelectionIntent.self,
          provider: Provider()
        ) { entry in
            WeatherAppWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("Weather Widget")
        .description("Forecasts in your location.")
        .supportedFamilies([.systemMedium, .systemSmall])
    }
}

.intentdefinition file:

enter image description here

enter image description here



Solution 1:[1]

struct LargeWidgetEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationIntent
}

Use configuration

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sanket Shah