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

SOLVED: How to save data for One-to-many relationships with Core Data

Forums > SwiftUI

Hi.

Maybe it's elementary, but I can't figure out how to do it. After studying the One-to-many relationships with Core Data lesson, I created a project by slightly changing the display of the view and adding a window for creating a new candy.

How can I save this candy to the country I went to via the NavigationLink?

List {
            ForEach(countries, id: \.self) { country in
                NavigationLink(country.wrappedFullName) {
                    Form {
                        ForEach(country.candyArray,id: \.self) { candy in
                            Text(candy.wrappedName)
                        }
                        Button("Add Candy") {
                            presentingAddNewCandySheet.toggle()
                        }
                    }
                }
            }
        }

I create a new candy through

TextField("Candy name", text: $name)

The data is saved and a new candy appears, but a new country is also created

Button("Add") {
        let candy = Candy(context: moc)
        candy.name = name

        candy.origin = Country(context: moc) /// ?
        candy.origin?.shortName = "UK" /// ?
        candy.origin?.fullName = "United Kingdom" /// ?

        try? moc.save()
    }

What should be instead of these lines?

Thanks for the possible answers!

2      

Because the line

candy.origin = Country(context: moc) /// ?

evertime creates a new country instead of reusing an existing one.

In your View you would need something like a Picker to choose an existing country instead of creating a new one. You then need to assign the Country to origin.

3      

@Bnerd  

make a small func for your button with a candy: Candy parameter, try the below:

func addCandy(country: Country) {
let candy = Candy(context: moc)
        candy.name = name

        candy.origin = country

        try? moc.save()
}

Your updated Button in the toggle sheet:

Button("Add") {
        addCandy(country: country) // The country here is the one taken from your "ForEach(countries, id: \.self) { country in"
    }

3      

Yes, I made a picker for selection, it did not work correctly. And after your answer, I thought again and found the problem. Now everything seems to be working!

Here is the code for the picker and save (may be useful to someone)

@State var selection: Country?

Picker("Country", selection: $selection) {
    ForEach(countrys, id: \.self) { (country: Country) in
        Text(country.fullName!)
            .tag(country as Country?)
    }
}
Button("Add") {
    let candy = Candy(context: moc)
    candy.name = name
    candy.origin = Country(context: moc)
    candy.origin?.shortName = selection?.shortName
    candy.origin?.fullName = selection?.fullName ?? "New Country"

    try? moc.save()
}

2      

Tried the second answer option from @Bnerd too

Button("Add") {
   addCandy(country: country) /// Error: "Cannot find 'country' in scope"
}

I add var country = Country()

When you save Candy, the application crashes with a response:

Thread 1: "Illegal attempt to establish a relationship 'origin' between objects in different contexts...

2      

@Bnerd  

Let's say your pop up sheet is like the below:

struct AddCandyView: View {
    @Environment(\.managedObjectContext) var moc
    var selectedCountry: Country
    @State var name = ""

    var body: some View {
        VStack{
            TextField("Candy name", text: $name)
            Button("Add") {
                addCandy(country: selectedCountry)
            }
        }
    }

    func addCandy(country: Country) {
        let candy = Candy(context: moc)
        candy.name = name

        candy.origin = country

        try? moc.save()
    }
}

your .sheet should be within the Foreach like this:

NavigationLink(country.wrappedFullName) {
                            //previous code here.
                        }
                        .sheet(isPresented: $presentingAddNewCandySheet) {
                            AddCandyView(selectedCountry: country)
                        }

2      

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.

Click to save your free spot now

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.