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

Day 61 - Core Data implementation

Forums > 100 Days of SwiftUI

Hello,

First post here, so go easy! :)

I have made it up to Day 61, and CoreData is something I am really keen to learn thoroughly. I have previously developed a prototype of an app using CoreData using UIKit, but I am keen to learn SwiftUI now.

I've got the Friend app working fine with structs for the data and have converted the main data into CoreData now. So far the app decodes the JSON, imports it into CoreData, and displays the information in the app using the CoreData Model. So far so good.

I'm at the point where I now want to click on a User, and it go through to the User detail screen, to show both the information on the User and the list of friends etc.

However, I believe the slight change that takes place during the conversion to CoreData is around pushing the data around the App.

I have fetched the data in the ContentView and it contains a FetchRequest variable of all the users. Now when I click on a user, I am struggling to push the data through to the DetailView. Am I even supposed to push the data, or should I be running a new fetch request inside the detail view based on the user selected?

Previously I pushed the user through to the detail view, and in the init() of the detail view used the ID's of the friends to create a new array of the users that were the friends of the User. However when I try and push the fetch request through now, I get the following error :

Cannot convert value of type 'FetchedResults<UserCD>' to expected argument type '[UserCD]

So do I run a new fetch request in the detail view? Or am I missing something? It doesn't feel like the moving of data around in an app using CoreData is really covered in the tutorials up to the challenge so I am struggling a little.....

I guess what I'd like help on is the core (pardon the pun) concept of using CoreData in an app with multiple views.

Thanks in advance, Chris.

3      

Hi Chris,

I think I'm having the same problem you had trying to pass my fetch results using NavigationLink from ContentView to DetailView. Were you able to solve this? Please let me know.

3      

hi Chris,

i would start by simply passing a selected user to a DetailView, and let the DetailView then read the friends from the user without another core data fetch. perhaps the display of all users is something like this:

ForEach(users) { user in
  NavigationLink(destination: DetailView) { 
    SomeRowView(user)
  }
}

and so the DetailView would be something like this:

struct DetailView: View {

  var user: User
  var body: some View {
    Text(user.name)
    // display of other data
    List {
      ForEach(friends(user)) { friend in
        SomeRowView(friend)
      }
    }
  }

  func friends(_ user: User) -> [Friend] {
    (friends as? Set<Friend>)?.sorted() ?? [ ] // assumes Friend is comparable and friends is the relationship name
  }
}

there's a little ugliness in the friends() function because assuming you have named the relationship for friends as friends in your CD model, it comes across as an NSSet? and needs to be converted to something of type [Friend]. (sorting is up to you, but it would seem convenient to make the Friend class Comparable.)

now there are two problems to consider.

  • if the data for a User is changed elsewhere in the app or even within the DetailView itself (perhaps by adding a friend), the DetailView may not update correctly unless you mark the user parameter as an @ObservedObject.
  • if the user in the DetailView can be deleted somewhere outside the DetailView or even within the DetailView itself, having an @ObservedObject reference to the deleted user will likely crash your app. be sure you nil-coalesce all the properties of a user in the DetailView, because SwiftUI may call the body even with a deleted (class) object ... before SwiftUI and Core Data get synched up ... and so all properties of the object will (likely) be nil.

you might want to take a look at my ShoppingList14 project, where i struggled for some time to get the right protocol. lots of comments (although i have not reviewed them carefully recently). i also have the additional functionality of providing a DetailView with default parameters when there is no user ... making the DetailView be, effectively, an "add new user" view that can be opened in a sheet (and not through a navigation link).

hope that helps,

DMG

Edit after the fact: i forgot to mention that if you make a change to the friends of a user, it may not necessarily trigger an update for some views where the user is being observed, depending on what you show. if changes to the user's friends don't get updated on screen, be sure to do an explicit objectWillChange.send() for the user.

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.