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      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

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.