I have an object called Item with two attributes, name (String) and value (Double). Given an array of Items I need combine the values of all items with the same name and keep the items with no duplicates. For example, say there were 4 items in the array and two of them named "Test" and the others "Object" and "Item". "Object" and "Item" would remain in the list, but the values of the two "Test"s would be combined into one item with the same name "Test".
I've included the following code for a visual representation.
Delete the comments as you read them to clean up. They're just there to clear up any confusion. Leave a comment if you have any questions. Thanks for the help!
Content View:
import SwiftUI
import CoreData
struct ContentView: View {
@Environment(\.managedObjectContext) var managedObjContext
@ObservedObject var persistence = PersistenceController.shared
@State private var items = PersistenceController.shared.getItems()
@State var isAddViewShowing = false
var body: some View {
NavigationView{
List{
Section{
ForEach(items) { item in //Displays the list of items
HStack{
Text(String(item.name!))
Spacer()
Text(String(Int(item.value)))
}
}
.onDelete(perform: { indexSet in
deleteItem(indexSet: indexSet)
})
}
}
.navigationBarTitle("Items")
.navigationBarItems(leading: combineItemsButton, trailing: addButton)
.sheet(isPresented: $isAddViewShowing){ //displays the view to add an item
AddView()
.onDisappear(perform: {
items = persistence.getItems() //"refreshes" the list of items
})
}
}
}
var combineItemsButton: some View{
Button(action:{
//combine duplicates here
persistence.contextSave()
items = persistence.getItems()
}){
Text("Combine Duplicates")
.bold()
}
}
var addButton: some View{
Button(action:{
isAddViewShowing.toggle()
}){
Text("Add Item")
.bold()
}
}
func deleteItem(indexSet: IndexSet){
withAnimation{
indexSet.map {
items[$0]
}
.forEach(managedObjContext.delete)
persistence.contextSave()
items = persistence.getItems()
}
}
}
Add View:
struct AddView: View{
@Environment(\.dismiss) var dismiss
@ObservedObject var persistence = PersistenceController.shared
@State var name: String = ""
@State var value = ""
@State private var alertMessage = ""
@State private var showAlert = false
var body: some View{
NavigationView{
Form{
TextField("Item Name", text: $name)
TextField("Item Value", text: $value)
.keyboardType(.decimalPad)
}
.navigationBarTitle("Add Item")
.navigationBarItems(leading: dismissButton, trailing: submitButton)
}
}
var submitButton: some View{
Button(action: {
if (name == ""){ //ensures the item has a name
alertMessage="Your recipe needs a name"
showAlert.toggle()
} else {
persistence.addItem(name: name, value: Double(value) ?? 2)
dismiss()
}
}){
Text("Submit")
.bold()
}
.alert(alertMessage, isPresented: $showAlert){
Button("OK",role: .cancel){}
}
}
var dismissButton: some View{
Button(action: {
dismiss()
}){
Text("Cancel")
.bold()
}
}
}
Persistence File:
import CoreData
class PersistenceController : ObservableObject{
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "Test")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
}
func getItems() -> [Item] { //fetches items
let context = container.viewContext
var request = NSFetchRequest<Item>()
request = Item.fetchRequest()
request.entity = NSEntityDescription.entity(forEntityName: "Item", in: context)
do {
let items = try context.fetch(request)
if items.count == 0 { return []}
return items.sorted(by: {$0.name! > $1.name!})
} catch {
print("**** ERROR: items fetch failed \(error)")
return []
}
}
func addItem(name: String, value: Double){
let context = container.viewContext
let item = Item(context: context)
item.id = UUID()
item.name = name
item.value = value
contextSave()
}
func contextSave() {
let context = container.viewContext
if context.hasChanges {
do {
try context.save()
self.objectWillChange.send()
} catch {
print("**** ERROR: Unable to save context \(error)")
}
}
}
}
Data Model:
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
How do you convert an image into binary data so that it can be saved in core data? I already have the image I simply need to add it to an entity in my core data model.
Any help would be greatly appreciated. Thanks!
So I want to implement the same feature many apple made have which is an gray list of options when something is held. An example of this is when you hold down an iMessage chat before you open it and it gives the options to “Pin”, “Hide Alerts”, and “Delete” and shown here:
Additionally when you hold down an app as if you were going to delete it a menu of options show up:
Using a button how can I do this on a long hold? Any help or any direction toward help is greatly appreciated. All the best!
I need to be able to search my list of recipes given a string. I’m unsure how to filter a data model in core data though. I tried a ForEach(container){ recipe in, but it said it gave me an error. Anyone know the correct way in the scrappy way doesn’t work? Thanks
data controller:
import Foundation
import CoreData
class DataController: ObservableObject {
let container = NSPersistentContainer(name: "RecipeModel")
init() {
container.loadPersistentStores { desc, error in
if let error = error {
print("Failed to load the data \(error.localizedDescription)")
}
}
}
func save(context: NSManagedObjectContext) {
do {
try context.save()
print("Data saved")
} catch {
print("The data could not be saved")
}
}
func addRecipe(title: String, ingredients: [String], instructions: [String], notes: String, context: NSManagedObjectContext){
let recipe = Recipe(context: context)
recipe.id = UUID()
recipe.date = Date()
recipe.title = title
recipe.ingredients = ingredients
recipe.instructions = instructions
recipe.notes = notes
save(context: context)
}
func editRecipe(recipe: Recipe, title: String, ingredients: [String], instructions: [String], notes: String, context: NSManagedObjectContext){
recipe.title = title
recipe.ingredients = ingredients
recipe.instructions = instructions
recipe.notes = notes
save(context: context)import Foundation
}
func updateDate(recipe: Recipe, context: NSManagedObjectContext){
recipe.date=Date()
save(context: context)
}
}
So I have a sheet View for when I add a recipe to my program, but when I add an instruction I want the user to be able to click their entry and check it to see if it is correct so what I’ve done is add a text view to enlarge it, but when I go to the view it shows the nav bar of the previous view like this:
This only happens when I use a sheet.
So I’ve looked this up so many times and tried every way I’ve found using a @State variable and nothing works. I need a button that toggles between SystemImage: “Star” to SystemImage: “Star.fill” when clicked. And I want it to happen when it’s clicked. Everything I’ve tried only changes when I close and reopen the view because it happens on appearance. Is there any way to make it change instantly? Thanks for any help!
I would like to implement the “Toolbar” kind of thing above the keyboard shown in the image that includes an up and down arrow to iterate through text fields and a done button to dismiss the keyboard. How do I do this? Thanks!
So I’ve looked this up so many times and tried every way I’ve found using a @State variable and nothing works. I need a button that toggles between SystemImage: “Star” to SystemImage: “Star.fill” when clicked. And I want it to happen when it’s clicked. Everything I’ve tried only changes when I close and reopen the view because it happens on appearance. Is there any way to make it change instantly? Thanks for any help!
I am trying to implement a search bar in my recipe storage app. I got recommended using the .filter function that I didn’t know could be used on FetchedResults. So I did and now I’m getting errors, but not ones saying that it isn’t in the scope so I believe this is possible, just now sure how.
The ForEach loop containing the filter:
•ForEach(recipes.filter({$0.title.contains(searchingFor)})) { recipe in
Note: Recipes is just a FetchedResults type and searchingFor is just a string that comes from the search bar.
The errors:
•Value of optional type 'String?' must be unwrapped to refer to member 'contains' of wrapped base type 'String'
•Chain the optional using '?' to access member 'contains' only for non-'nil' base values
•Force-unwrap using '!' to abort execution if the optional value contains 'nil'
Any help is greatly appreciated.
Whenever I open a text field almost anywhere I get this common toolbar above my keyboard with two arrows that iterate through text fields and a done button. Not just on Apple related things, but even when I search on google. Which leads me to believe this is a default object and that google did not take the time to make an identical keyboard toolbar as all of Apple’s. So how do I get this default toolbar?
toolbar:
So I have a core data entity titled recipe. I'm trying to make a search bar to search the list of recipes and my method of doing so is doing a fetch request of all objects and converting it to an array of those objects and then filtering the array and displaying the results. Any idea as to how to convert a type fetch results to an array?
PS: as I'm typing this it occurred to me I could just do a for each loop and add them to the array as I go, but is there a quicker way to do this? Like a function? Thanks!!!
I'm currently (obviously) building an app and I decided I prefer the dark mode theme more than default. Is there any way I could set it so that dark mode is the default color of the app?
Does anyone have any clue as to how to get rid of the grey background of my list? I've actually tried everything I could find online. .background(Color.clear), .backgroundStyle(.clear), init(){...}. nothing. I even tried replicating it in a new project and it didn't even show up there. Any idea as to how to get rid of this?
I need to enlarge my text field. So I tried using a frame, but that only put dead space around it. The problem with that is I want to be able to click anywhere inside the boarder and it pull up the keyboard. So I tried padding and that did the same thing. Also I need the text to start a new line after it fills the first one and to go for as long as they type. Thanks!
I need to edit an attribute of a core data entity fetched in a previous view. So I put var entityName: FetchedResults.Elementin the second view to get access to the entity. But when I do this it doesn't actually get the entity it gets a copy of the entity so when changes are made to it it doesn't actually change. Basically is there a way to pass a reference to an attribute of an object to a struct so that when you set that reference to a value the entity changes?
Any help would be greatly appreciated. All the best!