Search code examples
swiftswiftuiurlsessionobservableobject

Why do views from swift package seem to share an ObservableObject instance


My swift package UnsplashSwiftUI has a view called UnsplashRandom that uses a StateObject to asynchronously fetch data from the UnsplashApi. However, if you implement the view twice on the same page they load the same image even though they should be different.

I also tried an ObservedObject as follows, UnsplashApi is my ObservableObject.

@StateObject var api = UnsplashApi() // Original
@ObservedObject var api = UnsplashApi() // This didn't work either

Edit: Marking the StateObject private also didn't work

Edit: This is the implementation of UnsplashApi:

@MainActor
class UnsplashApi: ObservableObject {
    enum LoadingState {
        case idle
        case loading
        case loaded(UnsplashData)
        case failed(Error)
    }
    
    @Published var state: LoadingState = .idle
    
    func fetchImage(clientId: String, query: String, orientation: String) async {
        let baseUrl = URL(string: "https://api.unsplash.com/")
        guard var components = URLComponents(url: baseUrl!.appendingPathComponent("photos/random"), resolvingAgainstBaseURL: true)
        else { state = .failed(URLError(.badURL)); return }
        components.queryItems = [URLQueryItem(name: "client_id", value: clientId)]
        if query != "" {components.queryItems?.append(URLQueryItem(name: "query", value: query))}
        if orientation != "" {components.queryItems?.append(URLQueryItem(name: "orientation", value: orientation))}
        guard let url = components.url else { state = .failed(URLError(.badURL)); return }
        self.state = .loading
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            let response = try JSONDecoder().decode(UnsplashData.self, from: data)
            self.state = .loaded(response)
        } catch {
            state = .failed(error)
        }
    }
}

Solution

  • Your fetchImage method uses URLSession.shared. The shared URLSession uses a URLCache. So it's likely that the response to your first request for https://api.unsplash.com/photos/random is being stored in the cache and subsequent requests return the cached response.

    Try using URLSession(configuration: .ephemeral) instead of URLSession.shared.