After Purchasing Ebay How Can I Print Label Again
Updated for Xcode 12.0 and SwiftUI 2.0 ✅
Hello, and welcome to a new tutorial! Today nosotros will learn how to utilize the Core Data framework with SwiftUI to store and manage persistent data. The integration of Cadre Information into SwiftUI projects is surprisingly like shooting fish in a barrel. By creating a useful app for a pocket-size pizza restaurant, we will talk through all bones Grime operations (Create, Read, Update, and Delete Data) used in Core Data.
In this tutorial, we will explore:
- How Cadre Data and SwiftUI work together
- Creating and updating Cadre Data objects
- How to update views when stored data gets updated
- Using SwiftUI property wrappers for fetching Cadre Data objects
We will create a simple app for a pizza restaurant that waiters can use to accept and manage orders.
The finished app volition look like this:
Setting upwardly Core Data using SwiftUI and Xcode 12
To get started, open Xcode 12 and create a new "App" under "Multiplatform" or "iOS". You tin proper name your projection withal you desire, for instance, "PizzaRestaurant". But make certain to use SwiftUI every bit the "Interface" manner and SwiftUI App as the "Life Cycle" manner. Also, make sure that you lot cheque the "Employ Core Information" box. This will automatically set up the initial Core Data implementation for our app!

Make certain yous "reset" the ContentView by removing the generated code from it since we won't need information technology for our app.
import SwiftUI import CoreData struct ContentView: View { var trunk: some View { Text("Hello Earth!") } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
In the project navigator, you tin can spot the ".xcdatamodeld" file Xcode created for us. In this file, we set and manage the Entities of our Core Data information model for our SwiftUI app. If y'all are non familiar with the concept of Entities: You can call up of an entity as a class, and an attribute, as a property of that class. The only Entity we need for our app is for holding the unlike orders. Delete the default "Particular" Entity and create a new one past clicking on the big plus button at the bottom and then double-click on the created Entity to rename it to "Order".
We need to know the post-obit data about each order: The type of pizza the customer ordered, how many slices he wants to consume, and the number of the tabular array the client is sitting at. Each order should likewise accept a unique "id" and a "status" attribute for keeping track of whether the order is already completed. For theid, nosotros employ the UUID blazon (this automatically creates a unique id for us). For thenumberOfSclices we select Integer16 and for the rest Cord.

How Core Data works in SwiftUI and Xcode 12
That'due south information technology! We just finished setting up a basic Core Data model for holding the orders for our pizza restaurant app. Wasn't that easy? Allow's accept a look at how CoreData was implemented into our SwiftUI project by checking the "Utilise CoreData" box earlier.
To await behind the scenes, open thePizzaRestaurantApp.swift file. You already know that theApp struct primarily handles booting upwardly the initial view, which is theContentView by default. Considering we checked "Use CoreData" when creating our project earlier, Xcode created a belongings calledpersistenceController and applied an important modifier to the launchedContentView.
Let'due south take a look atpersistenceController property first.
allow persistenceController = PersistenceController.shared
This holding is assigned to aPersistenceController. Nosotros can find thisPersistenceController in thePersistence.swiftfile. ThePersistenceController struct independent in this file includes diverse properties.

Allow usa briefly review the most important ones. Thepreview property allows usa to utilise the CoreData functionality within preview simulators.
Note: Since we have deleted the default "Item" Entity and created a new i called "Order", nosotros have to brand a quick aligning hither. Delete the existing for-in loop and insert the following loops instead.
static var preview: PersistenceController = { //... for _ in 0..<x { let newItem = Order(context: viewContext) newItem.status = "pending" newItem.id = UUID() newItem.tableNumber = "12" newItem.pizzaType = "Margherita" newItem.numberOfSlices = 4 } //... }()
Thecontainer holding is the heart of thePersistenceController, which performs many unlike operations for us in the background when we store and call data. Almost importantly, thecontainer allows us to admission the so-calledviewContext, which serves as in an in-memory scratchpad where objects are created, fetched, updated, deleted, and saved back to the persistent store of the device where the app runs on.
Thecontainer gets initialized within thePersistenceController'due southinit function. In this, thecontainer property gets assigned to an NSPersistentContainer instance. We need to use the name of our ".xcdatamodeld" file, which is "Shared" (or *YourAppName* when you lot created a mere iOS App project), as the "name" statement.
init(inMemory: Bool = false) { container = NSPersistentContainer(proper noun: "PizzaRestaurant") //... }

At present, let's take a look at the.surroundings modifier applied to theContentView in our PizzaRestaurantApp struct.
ContentView() .surround(\.managedObjectContext, persistenceController.container.viewContext)
What does this.environmentmodifier do? Before ourContentView gets launched as the root view, information technology feeds the environment'smanagedObjectContext key with theviewContext we but talked about.
The "environment" is where organization-wide settings are saved, for example, Calendar, Locale, ColorScheme, and now, also theviewContext contained in thepersistenceController'southwardcontainer property. Each of these settings has its ain key; in our case, information technology'southward the.managedObjectContext cardinal.
Now, every view in our app tin can use theviewContext equally a "scratchpad" to call up, update, and store objects. Nosotros simply need to use themanagedObjectContext environs key for accessing it, equally you will see later on.
Don't worry if you are not familiar with this. The just matter you lot demand to remember is that we tin can use themanagedObjectContext for fetching and saving our orders. You'll run across how like shooting fish in a barrel this is in a moment.
Only beginning, we make a pocket-size adjustment to our CoreData information model.
Customizing our data model 🛠
Allow's hold on a second and reconsider choosing String as thestatus attribute's type. Each order'scondition should only be "Pending", "Preparing" and "Completed". Wouldn't be using an enum the better choice for this? Unfortunately, we can't create and use an enum inside the .xcdatamodeld file itself. But equally said, by creating and designing theOrder entity, Core Data created a respective form under the hood. We can admission and modify this class by clicking on theGild entity, going to the Xcode toolbar, and selecting Editor-"Create NSObjectManagedSubclass".
Later on creating the subclass, Xcode generated two files for usa. The Order+CoreDataClass.swift file holds the class itself, and theOrder+CoreDataProperties.swift contains its properties inside an extension.
Afterwards we created our data model'due south subclass, we demand to tell Xcode that the information model is no longer defined by the visual builder in our ".xcdatamodeld" file only, merely manually divers past the respective subclass we just created. To practise this, open the ".xcdatamodeld" file, click on theClub entity and open the data model inspector. Then choose "Manual/None" as the Codegen manner.

At this point, nosotros tin can remove the question marks from the Cord-type properties since we don't want them to be Optionals. Xcode should too create another extension adopting theIdentifiable protocol (this will make it easier for the states to useSocial club instances inside theContentView's List later). Since we declared anid property, we already adjust to this protocol.
extension Order: Identifiable { @nonobjc public course func fetchRequest() -> NSFetchRequest<Guild> { return NSFetchRequest<Order>(entityName: "Order") } @NSManaged public var pizzaType: Cord @NSManaged public var numberOfSlices: Int16 @NSManaged public var id: UUID? @NSManaged public var tableNumber: String @NSManaged public var condition: String } extension Gild : Identifiable { }
Below theOrder extension we can declare ourCondition enum with the three unlike cases.
enum Status: String { instance pending = "Awaiting" case preparing = "Preparing" case completed = "Completed" }
If we now try to use theStatus enum as thecondition' data type, we will get an fault.

You meet that @NSManagedObject properties can't be used with enums straight. But how else can we salve the status of an order in Core Information? Here'south a workaround: We go ahead with using our NSManaged condition property just not of ourStatus blazon. Instead, information technology should exist a String over again. Adjacent, we add another regular variable chosen "orderStatus". Because it's non an NSManaged belongings, it can be of the blazonCondition. Nosotros assign a setter and getter to ourorderStatus. When this property is set, it volition also gear up the NSManaged belongings accordingly. Using a getter, we endeavor to catechumen thestatus string to aCondition case when retrieving information technology.
extension Society { //... @NSManaged public var status: String var orderStatus: Status { set up { status = newValue.rawValue } get { Status(rawValue: status) ?? .pending } } }
Awesome, we finalized the Core Data model for our SwiftUI app!
Composing our UI 🎨
Important: Before moving on with composing our ContentView, we demand to make certain that its preview can access the view Context as well. Otherwise the SwiftUI preview will neglect when why try to implement CoreData functionality inside it. To practice this, nosotros use the viewContext of our PersistenceController and assign it to the environment'due southmanagedObjectContext key just as we did in our App struct.
struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView().surroundings(\.managedObjectContext, PersistenceController.preview.container.viewContext) } }
At present our ContentView preview is able to manage CoreData requests!
The ContentView of our pizza eating house app should comprise a list of all orders already taken which the corresponding waiter can manage. Since we can't store any data yet, we are using merely a test list for at present.
struct ContentView: View { var body: some View { Listing { Text("Sample order") } } }
We besides want to add together a navigation bar to our app. To do and so, we wrap our List into a NavigationView and use the .navigationBarTitle modifier.
NavigationView { List { Text("Sample order") } .navigationTitle("My Orders") }
The navigation bar should contain a button the waiter can use to add a new order.
List { Text("Sample lodge") } .navigationTitle("My Orders") .navigationBarItems(trailing: Push(action: { print("Open up guild sheet") }, label: { Image(systemName: "plus.circle") .imageScale(.large) }))
The preview sheet should wait similar this so far:

When nosotros tap on the Push button, we want to open a second view. For this, we create a new SwiftUI file and name it "OrderSheet. Nosotros want to display the OrderSheet every bit a modal view. To do this, we add a Land to our ContentView to control when the OrderSheet should exist displayed.
struct ContentView: View { @State var showOrderSheet = false var body: some View { //... } }
To display the OrderSheet every bit a modal view, we use the .sheet modifier.
List { Text("Sample gild") } //... .sheet(isPresented: $showOrderSheet) { OrderSheet() }
Whenever the showOrderSheet State is true the OrderSheet overlays the ContentView. Now we tin toggle the showOrderSheet State from our navigation bar push button.
.navigationBarItems(trailing: Button(activity: { showOrderSheet = true }, label: { Image(systemName: "plus.circle") .imageScale(.big) }))
For our OrderSheet view'due south body, we'll exist using the Class view to embed the user controls in, for example, a Picker with the different pizza options bachelor. To correspond the number of slices that the customer wishes to order, we use a Stepper. Finally, we use a TextField where the user can select the table number for the society.
Finally, we desire to save the data after the user taps on the "Add Lodge" button.
For the OrderSheet'south UI, you can use copy & paste the post-obit code:
struct OrderSheet: View { let pizzaTypes = ["Pizza Margherita", "Greek Pizza", "Pizza Supreme", "Pizza California", "New York Pizza"] @State var selectedPizzaIndex = 1 @State var numberOfSlices = 1 @State var tableNumber = "" var body: some View { NavigationView { Form { Section(header: Text("Pizza Details")) { Picker(selection: $selectedPizzaIndex, label: Text("Pizza Type")) { ForEach(0 ..< pizzaTypes.count) { Text(self.pizzaTypes[$0]).tag($0) } } Stepper("\(numberOfSlices) Slices", value: $numberOfSlices, in: 1...12) } Department(header: Text("Table")) { TextField("Table Number", text: $tableNumber) .keyboardType(.numberPad) } Button(action: { print("Save the order!") }) { Text("Add together Society") } } .navigationTitle("Add Order") } } }
The OrderSheet'due south preview should now look like this:

Saving information using Core Data and SwiftUI 🆕
Peachy, we're done composing our PizzaRestaurant app's interface, but goose egg gets saved and persisted yet. To alter this, we need to admission to the viewContext first to persistently salve a created order. Since, every bit nosotros saw in the offset, the managed object context is injected in our surroundings, we tin only access it by using the @Environment property wrapper inside our OrderSheet above its States.
@Environment(\.managedObjectContext) private var viewContext
At present that our OrderSheet has access to the device's "scratchpad" we are prepare to create an Order case when tapping on the "Add Order" Button. But first, we want to make sure that the tableNumber String is not empty past using a baby-sit statement.
Button(activeness: { baby-sit self.tableNumber != "" else {return} let newOrder = Order(context: viewContext) newOrder.pizzaType = self.pizzaTypes[self.selectedPizzaIndex] newOrder.orderStatus = .pending newOrder.tableNumber = self.tableNumber newOrder.numberOfSlices = Int16(self.numberOfSlices) newOrder.id = UUID() }) { Text("Add Order") }
Then nosotros're trying to salvage the created social club. If that fails, we print the respective error.
Push button(action: { //... newOrder.id = UUID() do { try viewContext.relieve() print("Society saved.") } catch { print(fault.localizedDescription) } }) { Text("Add Lodge") }
Later on the new order got saved, nosotros want to close the OrderSheet modal view. We can do this by adding the following @Environment property to our OrderSheet.
@Surround (\.presentationMode) var presentationMode
By referring to this property we can manually close the modal view:
do { endeavor viewContext.save() print("Social club saved.") presentationMode.wrappedValue.dismiss() } catch { print(error.localizedDescription) }
Okay, permit'due south run our app to run into if that works. Note that the preview canvas isn't able to simulate CoreData'due south functionality. Therefore, nosotros demand to run the app in the regular simulator. Click on the navigation bar button and fill out the OrderSheet form. So click on "Add Society". We saved the created order and dismissed the OrderSheet. Nonetheless, our ContentView's List is notwithstanding displaying its sample row.
Fetching and displaying stored orders 📖
To modify this, our ContentView needs to read out the saved orders. Achieving this functionality is quite simple by using a @FetchRequest property. But first, our ContentView itself requires admission to the viewContext. We do this by using the @Environment property once again. Below the ContentView'southward @Environment property, insert the following properties:
@Environment(\.managedObjectContext) individual var viewContext @FetchRequest(entity: Order.entity(), sortDescriptors: [], predicate: NSPredicate(format: "status != %@", Status.completed.rawValue)) var orders: FetchedResults<Guild>
The @FetchRequest permanently reads out the persistent storage for fetching stored orders from it. With the "predicate" argument, we filter out all orders already completed since we don't want them to display in our ContentView's List. The @FetchRequest then passes the retrieved orders to the orders property. Whenever we save a new lodge, the @FetchRequest volition notice and add it to the orders data set. Similar to the State functionality, this causes the ContentView to renew its body.
Now we're set to display the fetched data within our List, like this:
Listing { ForEach(orders) { order in HStack { VStack(alignment: .leading) { Text("\(lodge.pizzaType) - \(society.numberOfSlices) slices") .font(.headline) Text("Table \(lodge.tableNumber)") .font(.subheadline) } Spacer() Button(activity: {impress("Update order")}) { Text(guild.orderStatus == .pending ? "Fix" : "Consummate") .foregroundColor(.blue) } } .frame(height: 50) } } .listStyle(PlainListStyle()) //...
Hint: The reason we use a ForEach loop inside the List instead of inserting the orders data set in the Listing itself will become articulate when deleting orders.
When nosotros run our app once again, we encounter that our @FetchRequest successfully retrieves the just saved order from the persistent storage.

Hint: Also, ourContentView preview shows us dissimilar orders. However, these are not the ones that are located in the device's persistent storage, e.g., the simulator. Rather, they are generated for exam purposes by thepreview holding of ourPersistenceController. Can you recollect when we adjusted the corresponding code at the beginning? The resulting sampleOrder instances are at present used by the preview simulator, which itself has no persistent storage.

Updating Core Information entries 🔄
The Button on the correct side of each row can exist used to update the itemOrder's condition. When we add together a newOrder, itsstatus is.awaiting. Therefore the Push button reads "Set". When the user taps on the Button we want to update thestatus to.preparing, and the Button should read "Complete". When the user taps once more, nosotros want theSocial club'scondition to be.completed, which causes the @FetchRequest to filter the Social club out.
To implement this functionality, we add the following function below our ContentView's torso.
func updateOrder(social club: Club) { let newStatus = order.orderStatus == .pending ? Condition.preparing : .completed viewContext.performAndWait { club.orderStatus = newStatus try? viewContext.save() } }
We can phone call the updateOrder function from our row's button with passing the detail order case:
Button(action: { updateOrder(order: lodge) }) { Text(lodge.orderStatus == .pending ? "Prepare" : "Complete") .foregroundColor(.blue) }
Now we can run the app and tap on the "Prepare" button to mark the currently pending club equally prepared. If we click on "Complete", the Guild will be filtered out and eventually removed from our List.
Deleting orders from the persistent storage 🗑
Deleting stored information is almost as unproblematic as updating it. All we have to do is to delete the specific Order from the viewContext. And then, since the @FetchRequest will automatically detect that the Guild was deleted, it will update our ContentView accordingly and remove the row from the table with a prissy default blitheness.
To let the user delete rows, we add the.onDelete modifier to the ForEach loop. We can't apply this modifier to Lists. This is why we inserted a ForEach loop inside the List.
Listing { ForEach(orders) { social club in //... } .onDelete { indexSet in for index in indexSet { viewContext.delete(orders[alphabetize]) } do { try viewContext.save() } catch { print(error.localizedDescription) } } }
The .onDelete modifier detects the row(s) the user wants to delete by swiping and uses in that location index/indices to remove the respective Order entries from the viewContext.
If we run the application now, we can see that we can hands delete the order by swiping a row.

Decision 🎊
That's it. We finished our small pizza restaurant app! You learned how to utilise Core Data in SwiftUI to shop information persistently. We talked through all basic Grime operations: Creating, reading, updating, and deleting information. We also understood what a managedObjectContext is and how we can fetch stored information by using SwiftUI's @FetchRequest.
Nosotros've uploaded the whole source code of this app to GitHub.
If y'all liked this tutorial, feel gratuitous to check out our Mastering SwiftUI eBook. In this book, we besides created a To-do app past using the mentioned Core Data functionalities!
I promise you enjoyed this tutorial! If you want to learn more well-nigh SwiftUI, bank check out our other tutorials! Also, make sure you follow us on Instagram and subscribe to our newsletter to not miss whatsoever updates, tutorials, and tips most SwiftUI and more!
Source: https://blckbirds.com/post/core-data-and-swiftui/
Post a Comment for "After Purchasing Ebay How Can I Print Label Again"