WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Core Data - Linking saved item to something else

Forums > SwiftUI

HI All,

I have an app that lets you create a box, open the box and create items in that box.

I have the functionality that creates the box, lets me go into the box and create an item

The problem is, i am not telling the item which box it belongs to.

How would i go about telling the item which box it belongs to. I assume that i have to pass the id from the "select your box" view to the "put items in the box" view.

My item has id and box_id fields, my box has an id field and i have a relationship set up between box and item.

Any help would be greatly appreciated.

3      

hi,

sounds like you're using CoreData (you said "relationship"); ViewA is a list of boxes; and ViewB is a list of items in a selected box (where you can manage the items in the box).

if that's the case, you would do a @FetchRequest in ViewA to pull the list of boxes; and upon selecting one, pass the selected box object to ViewB. ViewB would then list out the items associated with the box using the CoreData relationship, plus provide the capability to manipulate those items (add, update, delete).

to move forward, we'll need to see some code (the CoreData classes for a Box and an Item would be helpful).

Added Note: Paul's Projects 11 & 12 in the 100 days of SwiftUI are quite relevant here.

hope that helps,

DMG

3      

Hi Everyone, I'm having the same issue except that my one-to-many relationship is a business register of all visitors.

I've based it on projects 11 & 12 as you mentioned. The code unfortunately brakes when i need to add the business before i create visitors.

Business Entity (one-to-many): fullName (constraint) shortName

Visitor (one-to-one): @NSManaged public var date: Date? @NSManaged public var email: String? @NSManaged public var id: String? @NSManaged public var name: String? @NSManaged public var phone: String? @NSManaged public var surname: String? @NSManaged public var temp: NSDecimalNumber? @NSManaged public var business: Business?

When program starts up, in contentview:

.onAppear(perform: {
    // Initially no business will exist.
    if (self.businesses.isEmpty) { self.showingProfile = true } else {
        return
    }
})

I then add the business:

Button(action: {
    let business = Business(context: self.managedObjectContext)
        business.fullName = self.fullName
        business.shortName = self.shortName

    do {
        try self.managedObjectContext.save()
        print("Saved: \(business)")
    } catch {
        // handle the Core Data error
        print("Failed to save data: \(error.localizedDescription)")

I then capture the visitor details, replacing the hardcoded business details with that of the captured info:

let visitor = Visitor(context: self.managedObjectContext)
                visitor.id = details[0] //Int64(id.replacingOccurrences(of: " ", with: "_")) ?? 0
                visitor.surname = details[1].lowercased().capitalized
                visitor.name = details[2].lowercased().capitalized
                visitor.date = Date()
//                visitor.business? = self.businesses.first!
                visitor.business? = Business(context: self.managedObjectContext)
//                visitor.business?.fullName = "Edge Technology Solutions (Pty) LTD"
//                visitor.business?.shortName = "EDGE"
                visitor.business?.shortName = self.businesses.first?.shortName ?? "Empty"
                visitor.business?.fullName = self.businesses.first?.fullName ?? "Empty"

            do {
                try self.managedObjectContext.save()
                print("Saved: \(visitor)")

Been stuck on this for a couple of days, any help would be appreciated, thanks.

3      

hi,

so, it sounds like the main screen is ContentView, maybe with a list of Visitors, and somewhere in that UI, there's a button to add a new Visitor? if that's the case, bring up a sheet to get the customer details (maybe a Form), and in that screen, have a "Select Business" that displays a picker of known businesses to associate with the Visitor, and also a Button "or Create New Business" right there on the spot to associate with the Visitor. (i.e., bring up another sheet on top of the first).

alternatively, you could set visitor.business = nil upon Customer creation, and (depending on how you set up the overall UI) come back after the fact to set that either from a known list of Businesses or to create a new Business.

FWIW (apologies to some readers who have seen this before!), i have a project that i'm happy to have you take a look at on Github called ShoppingList. it has almost all of the components of what you're doing (perhaps not on the same scale of potential data), and addresses this problem of adding what you call a new Visitor (i call it a ShoppingItem) and associating it with a Business (i call it a Location).

my solution, at the moment, is to let the user pick from a known list of Businesses/Locations, or else default to a speically-identified "Uknown" Business/Location. I can later add the new Business/Location, then make the association at that time.

in fact, you've now given me a reason to spend some time with my project later today to rethink this.

hope that helps,

DMG

4      

Thanks @delawaremathguy, I'll have a look at your code tonight and share my solution if it is at all diferent from yours.

3      

@delawaremathguy, thanks for all your help. Was worried when i saw your code as I dont have experience with JSON data. I definately understand everything much better after going through your code. I still do not follow everything you have done but it led me to this solution. Which i think was quite clean.

let visitor = Visitor(context: self.managedObjectContext)
    visitor.id = details[0]
    visitor.surname = details[1].lowercased().capitalized
    visitor.name = details[2].lowercased().capitalized
    visitor.date = Date()
let business = self.businesses.first!
    business.addToVisitor(visitor)

3      

hi,

your last code looks fine. in fact, you're creating a default Business when ContentView appears (if it does not already have one), and referencing it as self.businesses.first!.

these two lines are where you make the connection to this default Business with a new Customer:

let business = self.businesses.first!
business.addToVisitor(visitor)

i believe you could write this as well (CoreData always fills in the inverse of a relationship when you set it in one direction).

visitor.business = self.businesses.first!

i agree: much cleaner.

also, just one thing about my suggestion of "bringing up a sheet." if you do this, you'll need to pass along the managedObjectContext of your ContentView to the sheet with something like (sheets don't inherit the environment of the parent):

AddNewBusiness().environment(\.managedObjectContext, self.managedObjectContext)

and one last thing: Picker does not really work in a sheet (it want to be in a NavigationView somewhere).

good luck,

DMG

4      

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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.