UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: [SwiftData] Querying for a single object in Day 61

Forums > 100 Days of SwiftUI

Hi! I am currently solving the challenge for Day 61, so I'm adapting my previous work to support SwiftData. My problem is more on the design side than on the coding one.

What I had previously done was to create a UserCollection Observable class that contained the list of users and a boolean indicating a possible error. I did so because it was then easy to create an initializer that fetches the data only once.

Now, I am finding it a bit hard to adapt this architecture to support SwiftData. What I initially tried (after of course adapting the User and Friend classes to be Models) was to make the UserCollection class a Model too, but I quickly discovered the the @Query macro only works with arrays and such (from what I understood, or at least I only found examples of this kind). So something like @Query var userCollection: UserCollection in ContentView would not work.

So now the obvious solution would be to move the list of users and the download of the data to the ContentView itself, which would allow me to use the @Query macro as usual, but I have to say I quite liked the architecture I had sketched out. Is there any possible alternative I'm missing to keep what (to me) is conceptually one thing (a set of users and its related data) together?

I'll attach the original UserCollection class, which I would like to adapt to SwiftData.

import Foundation

@Observable
class UserCollection {
    var users: [User] = []
    var downloadError = false

    init() {
        Task {
            do {
                print("Downloading...")
                let url = URL(string: "https://www.hackingwithswift.com/samples/friendface.json")!
                let (data, _) = try await URLSession.shared.data(from: url)

                let decoder = JSONDecoder()
                decoder.dateDecodingStrategy = .iso8601

                let decodedData = try decoder.decode([User].self, from: data)
                self.users = decodedData
            } catch {
                print("Failed to load the users!")
                downloadError = true
            }
        }
    }
}

2      

I think you may want to use MVVM in this case. Similar to this post - https://www.hackingwithswift.com/quick-start/swiftdata/how-to-use-mvvm-to-separate-swiftdata-from-your-views

2      

@Obelix thanks for the detailed answer. Of course many of your observations are true for real projects and I simply did not consider them for this very quick challenge, but of course I know the importance of naming conventions and the convenience of separating the logic from the presentation code. My question was more on the "If this is possible, how do I do this?" side of things, meaning: I know it would be advisable not to introduce the "download" code in the View itself, but then I wouldn't know how to perform a SwiftData query inside a class.

@ygeras suggests using MVVM, but Paul himself writes in the article that doing so with SwiftUI and SwiftData creates even bigger problems. So my question is, where to draw the line? Especially in small and personal projects like I intend to develop, is it better to divide data and layout code or to accept some coupling for the sake of simplicity? Or are there other solutions I'm not aware of?

2      

Paul doesn't say it creates more problems :) he says it is more work invovled, as indeed @Query updates views automatically, without using it you have to handle tracking of any changes yourself as @Query does that for you. And besides SwiftData is quite "young" yet so we definitely will see many additions and changes to that. But for small project I would go for simplicity, or for the sake of "broadening your horizons" why not to use more complex approaches. There is no one good answer for that. So it is up to you to decide in the end, and as long as you're satisfied with the result.

2      

@ygeras yeah, I meant problems as in "things to be taken care of". I'm starting to see that using MVVM or not is quite the debate in the SwiftUI world. Anyway thanks, I'll now go back to the project and see what fits best.

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.