Using Picker with Core Data - swift

I have seen a number of responses about similar issues on here, but the picker for $category in the code below doesn't seem to work. When I select the picker, I see the list of categoryNames, but when I choose one, it doesn't get populated into $category.
I have 2 CoreData entities:
Expenses
expenseAccount:String
expenseCategory:String
expenseCost:Double
expenseDate:Date
expenseId:UUID
expenseIsMonthly:Bool
expenseName:String
Categories
categoryName:String
import SwiftUI
import CoreData
struct ExpenseDetail: View {
#FetchRequest(
entity: Categories.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \Categories.categoryName, ascending: true)
]
)
private var result: FetchedResults<Categories>
var logToEdit: Expenses?
#Environment(\.managedObjectContext) var context
#State var name: String = ""
#State var amount: String = ""
#State var category: String = ""
#State var date: Date = Date()
#State var account: String = ""
#State var isMonthly: Bool = false
var currencyFormatter: NumberFormatter = {
let f = NumberFormatter()
f.numberStyle = .currency
return f
}()
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
Form{
TextField("Expense Name", text: $name)
Section{
HStack{
TextField("$\(amount)", text: $amount)
.keyboardType(.decimalPad)
.textFieldStyle(PlainTextFieldStyle())
.disableAutocorrection(true).multilineTextAlignment(.leading)
}
DatePicker(selection: $date, displayedComponents: .date) {
Text("Date")
}.onAppear{self.hideKeyboard()}
Picker(selection: $category, label: Text("Category")) {
ForEach(result) { (log: Categories) in
Text(log.categoryName ?? "No Category").tag(log.categoryName)
}
}
Picker(selection: $account, label: Text("Account")) {
ForEach(result) { (log: Categories) in
self.Print("\(log.categoryName ?? "")")
Button(action: {
// TODO: Implement Edit
}) {
Text(log.categoryName!.capitalized).tag(self.category)
}
}
}
Toggle(isOn: $isMonthly) {
Text("Monthly Expense")
}.toggleStyle(CheckboxToggleStyle())
}
Section{
Button(action: {
onSaveTapped()
}) {
HStack {
Spacer()
Text("Save")
Spacer()
}
}
}
Section{
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Spacer()
Text("Cancel").foregroundColor(.red)
Spacer()
}
}
}
}.navigationBarTitle("Add Expense")
}
}
private func onSaveTapped() {
let expenseLog: Expenses
if let logToEdit = self.logToEdit {
expenseLog = logToEdit
} else {
expenseLog = Expenses(context: self.context)
expenseLog.expenseId = UUID()
}
expenseLog.expenseName = self.name
expenseLog.expenseCategory = self.category
print("\(expenseLog.expenseName ?? "") category Picker: \(self.category)")
print("\(expenseLog.expenseName ?? "") ExpenseCategory: \(expenseLog.expenseCategory!)")
expenseLog.expenseCost = Double(self.amount) ?? 0
print("\(expenseLog.expenseName ?? "") Amount: \(self.amount)")
print("\(expenseLog.expenseName ?? "")ExpenseCost: \(expenseLog.expenseCost)")
expenseLog.expenseDate = self.date
expenseLog.expenseAccount = self.account
expenseLog.expenseIsMonthly = self.isMonthly
do {
try context.save()
} catch let error as NSError {
print(error.localizedDescription)
}
self.presentationMode.wrappedValue.dismiss()
}
}

The type of the selection value is String while Category.categoryName is String?. Notice the added ?, this means it is an Optional.
It is the default type for CoreData, but you can remove the Optional value inside the model:
I would ask myself does a Category without a name make sense before doing this change. If it does, you will probably have to use another identifier for the selection.

Related

Having trouble with "Return from initializer without initializing all stored properties" error

Having trouble resolving this error "Return from initializer without initializing all stored properties"
Here is the code that prompted the error,
import SwiftUI
struct TaskEditView: View
{
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
#Environment(\.managedObjectContext) private var viewContext
#EnvironmentObject var dateHolder: DateHolder
#ObservedObject var notificationManager: NotificationManager
#State var selectedTaskItem: TaskItem?
#State var name: String
#State var desc: String
#State var dueDate: Date
#State var scheduleTime: Bool
init(passedTaskItem: TaskItem?, initialDate: Date)
{
if let taskItem = passedTaskItem
{
_selectedTaskItem = State(initialValue: taskItem)
_name = State(initialValue: taskItem.name ?? "")
_desc = State(initialValue: taskItem.desc ?? "")
_dueDate = State(initialValue: taskItem.dueDate ?? initialDate)
_scheduleTime = State(initialValue: taskItem.scheduleTime)
}
else
{
_name = State(initialValue: "")
_desc = State(initialValue: "")
_dueDate = State(initialValue: initialDate)
_scheduleTime = State(initialValue: false)
}
} //error appears right here
var body: some View
{
NavigationView{
Form
{
Section(header: Text("ToDo"))
{
TextField("Name", text: $name)
TextField("Description", text: $desc)
}
Section(header: Text("Deadline"))
{
Toggle("Schedule Time", isOn: $scheduleTime)
DatePicker("Date", selection: $dueDate, displayedComponents: displayedComps())
}
if selectedTaskItem?.isCompleted() ?? false
{
Section(header: Text("Completed"))
{
Text(selectedTaskItem?.completedDate?.formatted(date: .abbreviated, time: .shortened) ?? "")
}
}
Section()
{
Button("Save", action: saveAction)
.font(.headline)
.foregroundColor(.green)
.padding(.horizontal)
}
.navigationTitle("Create New ToDo 📝")
}
}
}
func displayedComps() -> DatePickerComponents
{
return scheduleTime ? [.hourAndMinute, .date] : [.date]
}
func saveAction()
{
withAnimation
{
if selectedTaskItem == nil
{
selectedTaskItem = TaskItem(context: viewContext)
}
selectedTaskItem?.created = Date()
selectedTaskItem?.name = name
selectedTaskItem?.desc = desc
selectedTaskItem?.dueDate = dueDate
selectedTaskItem?.scheduleTime = scheduleTime
dateHolder.saveContext(viewContext)
self.presentationMode.wrappedValue.dismiss()
}
let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: dueDate)
guard let hour = dateComponents.hour, let minute = dateComponents.minute else { return }
notificationManager.createLocalNotification(title: name, hour: hour, min: minute) { error in
if error == nil {}
}
}
}
struct TaskEditView_Previews: PreviewProvider {
static var previews: some View {
TaskEditView(passedTaskItem: TaskItem(), initialDate: Date())
}
}
I looked online and it said that I have to initialize all my proporties but im unsure how to do that for the
_selectedTaskItem
in the else statement.
Im very new to coding and much help would be appreciated
Thanks
Yes, you still need to initialize selectedTaskItem, even if its initial value is nil.
The good news is that passedTaskItem works in both cases, so you can move that initialization out of the if clause:
init(passedTaskItem: TaskItem?, initialDate: Date) {
_selectedTaskItem = State(initialValue: passedTaskItem)
if let taskItem = passedTaskItem {
_name = State(initialValue: taskItem.name ?? "")
// etc.

SwiftUI ToDoList with checkboxes?

I want to write a ToDoList in swiftUI with core data. Everything works so far but I want to have a checkbox next to each item it Signify whether it is completed or not.
I have added a property isChecked:boolean in core data but I don't know how to properly read it from the database. How to use a Toggle() in my case?
struct ContentView: View {
#Environment(\.managedObjectContext) var context
#FetchRequest(fetchRequest: ToDoListItem.getAllToDoListItems())
var items: FetchedResults<ToDoListItem>
#State var text: String = ""
var body: some View {
NavigationView {
List {
Section (header: Text("NewItem")){
HStack {
TextField("Enter new Item.",text: $text)
Button(action: {
if !text.isEmpty{
let newItem = ToDoListItem(context: context)
newItem.name = text
newItem.createdAt = Date()
// current date as created
newItem.isChecked = false
do {
try context.save()
} catch {
print(error)
}
// to clear the textField from the previous entry
text = ""
}
}, label: {
Text("Save")
})
}// end of vstack
}
Section {
ForEach(items){ toDoListItem in
VStack(alignment: .leading){
// to have a checkbox
Button {
toDoListItem.isChecked.toggle()
} label: {
Label(toDoListItem.name!, systemImage: toDoListItem.isChecked ? "checkbox.square" : "square")
}
if let name = toDoListItem.name {
// Toggle(isOn: toDoListItem.isChecked)
Text(name)
.font(.headline)
}
//Text(toDoListItem.name!)
//.font(.headline)
if let createdAt = toDoListItem.createdAt {
//Text("\(toDoListItem.createdAt!)")
Text("\(createdAt)")
}
}
}.onDelete(perform: { indexSet in
guard let index = indexSet.first else {
return
}
let itemToDelete = items[index]
context.delete(itemToDelete)
do {
try context.save()
}
catch {
print(error)
}
})
}
}
.navigationTitle("To Do List")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
ToDoListItem.swift
class ToDoListItem: NSManagedObject,Identifiable {
#NSManaged var name:String?
#NSManaged var createdAt:Date?
#NSManaged var isChecked:Bool
// mapped to the entry properties in database
}
extension ToDoListItem {
static func getAllToDoListItems() -> NSFetchRequest<ToDoListItem>{
let request:NSFetchRequest<ToDoListItem> = ToDoListItem.fetchRequest() as!
NSFetchRequest<ToDoListItem>
// cast as todolist item
let sort = NSSortDescriptor(key: "createdAt", ascending: true)
// above order of sorting
request.sortDescriptors = [sort]
return request
}
}
Should isChecked be an optional as well?

Listing CoreData object through Relationship

I had this working without CoreData relationships (multiple fetches), but it occurred to me that I should probably have relationships between these entities implemented, so that I can just fetch from a single entity to get all attributes.
When I fetch accountNames from the Accounts entity directly for my AccountsList.swift (to create accounts) - it works just fine, but when I try to call them through the relationship (originAccounts), it doesn't show anything in the list. Same issue for the Categories picker.
I have 3 CoreData entities, and two Pickers (for category and account)
Expenses
expenseAccount:String
expenseCategory:String
expenseCost:Double
expenseDate:Date
expenseId:UUID
expenseIsMonthly:Bool
expenseName:String
Categories
categoryName:String
Accounts
accountName:String
Expenses has a many to one relationship with both Accounts and Categories
import SwiftUI
import CoreData
struct ExpenseDetail: View {
#Environment(\.managedObjectContext) var context
#Environment(\.presentationMode) var presentationMode
#FetchRequest(fetchRequest: Expenses.expensesList)
var results: FetchedResults<Expenses>
var logToEdit: Expenses?
#State var name: String = ""
#State var amount: String = ""
#State var category: String?
#State var date: Date = Date()
#State var account: String?
#State var isMonthly: Bool = false
var currencyFormatter: NumberFormatter = {
let f = NumberFormatter()
f.numberStyle = .currency
return f
}()
var body: some View {
NavigationView {
Form{
TextField("Expense Name", text: $name)
Section{
HStack{
TextField("$\(amount)", text: $amount)
.keyboardType(.decimalPad)
.textFieldStyle(PlainTextFieldStyle())
.disableAutocorrection(true).multilineTextAlignment(.leading)
}
DatePicker(selection: $date, displayedComponents: .date) {
Text("Date")
}.onAppear{self.hideKeyboard()}
Picker(selection: $category, label: Text("Category")) {
ForEach(results) { (log: Expenses) in
Text(log.originCategories?.categoryName ?? "No Category").tag(log.originCategories?.categoryName)
}
}
Picker(selection: $account, label: Text("Account")) {
ForEach(results) { (log: Expenses) in
Text(log.originAccounts?.accountName ?? "No Account").tag(log.originAccounts?.accountName)
}
}
Toggle(isOn: $isMonthly) {
Text("Monthly Expense")
}.toggleStyle(CheckboxToggleStyle())
}
Section{
Button(action: {
onSaveTapped()
}) {
HStack {
Spacer()
Text("Save")
Spacer()
}
}
}
Section{
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Spacer()
Text("Cancel").foregroundColor(.red)
Spacer()
}
}
}
}.navigationBarTitle("Add Expense")
}
}
private func onSaveTapped() {
let expenseLog: Expenses
if let logToEdit = self.logToEdit {
expenseLog = logToEdit
} else {
expenseLog = Expenses(context: self.context)
expenseLog.expenseId = UUID()
}
expenseLog.expenseName = self.name
expenseLog.originCategories?.categoryName = self.category
expenseLog.expenseCost = Double(self.amount) ?? 0
expenseLog.expenseDate = self.date
expenseLog.originAccounts?.accountName = self.account
print("\(self.account ?? "NoAccountValue")")
expenseLog.expenseIsMonthly = self.isMonthly
do {
try context.save()
} catch let error as NSError {
print(error.localizedDescription)
}
self.presentationMode.wrappedValue.dismiss()
}
}
#if canImport(UIKit)
extension View {
func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
#endif
struct ExpenseDetail_Previews: PreviewProvider {
static var previews: some View {
ExpenseDetail()
}
}
struct CheckboxToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
return HStack {
configuration.label
Spacer()
Image(systemName: configuration.isOn ? "checkmark.square" : "square")
.resizable()
.frame(width: 22, height: 22)
.onTapGesture { configuration.isOn.toggle() }
}
}
}
expensesList fetch details, if needed
static var expensesList: NSFetchRequest<Expenses> {
let request: NSFetchRequest<Expenses> = Expenses.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "expenseName", ascending: true)]
return request
}

2 Pickers fetching from 2 Core Data Entities

Building my first app here, so I'm curious if I'm going about this the right way.
My app allows the user to create Accounts and Categories before creating an Expense object, which will allow the user to select an account and category to apply to the expense.
How can I fetch from both entities (Accounts and Categories) in a single view?
I tried including all Attributes under the Expenses entity, but it seems that when I save, it creates a new Expense in my ExpenseList view.
I have 3 CoreData entities, and two Pickers (for category and account)
Expenses
expenseAccount:String
expenseCategory:String
expenseCost:Double
expenseDate:Date
expenseId:UUID
expenseIsMonthly:Bool
expenseName:String
Categories
categoryName:String
Accounts
accountName:String
import SwiftUI
import CoreData
struct ExpenseDetail: View {
#FetchRequest(
entity: Categories.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \Categories.categoryName, ascending: true)
]
)
private var result: FetchedResults<Categories>
var logToEdit: Expenses?
#Environment(\.managedObjectContext) var context
#State var name: String = ""
#State var amount: String = ""
#State var category: String = ""
#State var date: Date = Date()
#State var account: String = ""
#State var isMonthly: Bool = false
var currencyFormatter: NumberFormatter = {
let f = NumberFormatter()
f.numberStyle = .currency
return f
}()
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
Form{
TextField("Expense Name", text: $name)
Section{
HStack{
TextField("$\(amount)", text: $amount)
.keyboardType(.decimalPad)
.textFieldStyle(PlainTextFieldStyle())
.disableAutocorrection(true).multilineTextAlignment(.leading)
}
DatePicker(selection: $date, displayedComponents: .date) {
Text("Date")
}.onAppear{self.hideKeyboard()}
Picker(selection: $category, label: Text("Category")) {
ForEach(result) { (log: Categories) in
Text(log.categoryName ?? "No Category").tag(log.categoryName)
}
}
Picker(selection: $account, label: Text("Account")) {
ForEach(result) { (log: Categories) in
self.Print("\(log.categoryName ?? "")")
Button(action: {
// TODO: Implement Edit
}) {
Text(log.categoryName!.capitalized).tag(self.category)
}
}
}
Toggle(isOn: $isMonthly) {
Text("Monthly Expense")
}.toggleStyle(CheckboxToggleStyle())
}
Section{
Button(action: {
onSaveTapped()
}) {
HStack {
Spacer()
Text("Save")
Spacer()
}
}
}
Section{
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Spacer()
Text("Cancel").foregroundColor(.red)
Spacer()
}
}
}
}.navigationBarTitle("Add Expense")
}
}
private func onSaveTapped() {
let expenseLog: Expenses
if let logToEdit = self.logToEdit {
expenseLog = logToEdit
} else {
expenseLog = Expenses(context: self.context)
expenseLog.expenseId = UUID()
}
expenseLog.expenseName = self.name
expenseLog.expenseCategory = self.category
print("\(expenseLog.expenseName ?? "") category Picker: \(self.category)")
print("\(expenseLog.expenseName ?? "") ExpenseCategory: \(expenseLog.expenseCategory!)")
expenseLog.expenseCost = Double(self.amount) ?? 0
print("\(expenseLog.expenseName ?? "") Amount: \(self.amount)")
print("\(expenseLog.expenseName ?? "")ExpenseCost: \(expenseLog.expenseCost)")
expenseLog.expenseDate = self.date
expenseLog.expenseAccount = self.account
expenseLog.expenseIsMonthly = self.isMonthly
do {
try context.save()
} catch let error as NSError {
print(error.localizedDescription)
}
self.presentationMode.wrappedValue.dismiss()
}
}
ExpenseList code, if needed:
NavigationView{
if #available(iOS 14.0, *) {
List{
ForEach(result) { (log: Expenses) in
self.Print("\(log.expenseName ?? "") expenseCost: \(log.expenseCost)")
self.Print("\(log.expenseName ?? "") amountText: \(log.amountText)")
Button(action: {
// TODO: Implement Edit
}) {
HStack(spacing: 16) {
VStack(alignment: .leading, spacing: 8) {
Text(log.nameText).font(.headline)
Text(log.dateText).font(.caption)
}
Spacer()
VStack(alignment: .trailing, spacing: 8){
Text(log.amountText).font(.headline)
Text(log.expenseAccount?.capitalized ?? "").font(.caption)
Text(log.expenseCategory ?? "No Category")
}
}
.padding(.vertical, 2)
}
}.onDelete(perform: onDelete)
}.navigationTitle("Expense List")
.navigationBarItems(trailing:
Button(action: {
// toggles the value of our bool from false to true,
// which will present our sheet.
self.addExpense.toggle()
}, label: {
Image(systemName: "plus.circle.fill")
})
.sheet(isPresented: $addExpense) {
ExpenseDetail()
}
)
} else {
// Fallback on earlier versions
}
}
}
Code used to save Categories:
private func onSaveTapped() {
let log: Categories
if let logToEdit = self.logToEdit {
log = logToEdit
} else {
log = Categories(context: self.context)
}
log.categoryName = self.category
do {
try context.save()
} catch let error as NSError {
print(error.localizedDescription)
}
}
}

How to properly group CoreData records by category in SwiftUI?

I am using CoreData. I have:
1 Entity: Todo
3 attributes: category (String), date (Date), title (String).
Module: Current Product Module
Codegen: Class Definition
I would like to build a simple ToDo app that looks like this:
To do items
Category
1. 3/26/20 To do item 1
2. 3/26/20 To do item 2
Category
1. 3/26/20 To do item 3
2. 3/27/20 To do item 4
I know there are similar questions, but I didn't find an answer on how to set everything using CoreData and SwiftUI.
I have most of the code done. Including adding items, saving to CoreData, deleting items.
ContentView.swift
Here I display the To do list. I have added the comments to problematic parts.
import SwiftUI
struct ContentView: View {
#Environment(\.managedObjectContext) var moc
#State private var date = Date()
#FetchRequest(
entity: Todo.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \Todo.date, ascending: true)
]
) var todos: FetchedResults<Todo>
#State private var show_modal: Bool = false
// let dictionary = Dictionary(grouping: Todo) { $0.category }
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .short
return formatter
}
var body: some View {
NavigationView {
List {
// Here I should sort by category
ForEach(self.todos, id: \.title) { todo in
// Here I should write category name instead of static text
Section(header: Text("Category")) {
ForEach(Array(self.todos.enumerated()), id: \.element) {(i, todo) in
NavigationLink(destination: TodoDetailsView(todo: todo)) {
HStack {
Text("\(i+1). ")
Text("\(todo.date ?? Date(), formatter: self.dateFormatter)")
Text(todo.title ?? "")
}
}
}
}
}
}
.navigationBarTitle(Text("To do items"))
.navigationBarItems(
trailing:
Button(action: {
self.show_modal = true
}) {
Text("Add")
}.sheet(isPresented: self.$show_modal) {
TodoAddView().environment(\.managedObjectContext, self.moc)
}
)
.listStyle(GroupedListStyle())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return ContentView().environment(\.managedObjectContext, context)
}
}
TodoAddView.swift
Here I add new items and save them to CoreData. This works OK.
import SwiftUI
struct TodoAddView: View {
#Environment(\.presentationMode) var presentationMode
#Environment(\.managedObjectContext) var moc
static let dateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
#State private var showDatePicker = false
#State private var title = ""
#State private var category = ""
#State private var date : Date = Date()
var body: some View {
NavigationView {
VStack {
HStack {
Button(action: {
self.showDatePicker.toggle()
}) {
Text("\(date, formatter: Self.dateFormat)")
}
Spacer()
}
if self.showDatePicker {
DatePicker(
selection: $date,
displayedComponents: .date,
label: { Text("Date") }
)
.labelsHidden()
}
TextField("title", text: $title)
TextField("category", text: $category)
Spacer()
}
.padding()
.navigationBarTitle(Text("Add to do item"))
.navigationBarItems(
leading:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Cancel")
},
trailing:
Button(action: {
let todo = Todo(context: self.moc)
todo.date = self.date
todo.title = self.title
todo.category = self.category
do {
try self.moc.save()
}catch{
print(error)
}
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Done")
}
)
}
}
}
struct TodoAddView_Previews: PreviewProvider {
static var previews: some View {
TodoAddView()
}
}
TodoDetailsView.swift
Here I display details of each item and can delete an item from there. This works good too.
import SwiftUI
struct TodoDetailsView: View {
#Environment(\.managedObjectContext) var moc
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var todo: Todo
static let dateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
#State private var showDatePicker = false
#State private var newDate : Date = Date()
#State private var newTitle = ""
#State private var newCategory = ""
var body: some View {
ScrollView {
VStack {
HStack {
Button(action: {
self.showDatePicker.toggle()
}) {
Text("\(newDate, formatter: Self.dateFormat)")
}
Spacer()
}
if self.showDatePicker {
DatePicker(
selection: $newDate,
displayedComponents: .date,
label: { Text("Date") }
)
.labelsHidden()
}
TextField("title", text: $newTitle, onCommit: {
self.todo.title = self.newTitle
try? self.moc.save()
}
)
TextField("category", text: $newCategory, onCommit: {
self.todo.category = self.newCategory
try? self.moc.save()
}
)
Spacer()
}
.padding()
.navigationBarTitle(Text("Details"))
.navigationBarItems(
trailing:
Button(action: {
self.moc.delete(self.todo)
do {
try self.moc.save()
self.presentationMode.wrappedValue.dismiss()
}catch{
print(error)
}
}) {
Text("Delete")
.foregroundColor(.red)
}
)
}
.onAppear {
self.newDate = self.todo.date ?? Date()
self.newTitle = self.todo.title ?? ""
self.newCategory = self.todo.category ?? ""
}
.onDisappear {
self.todo.date = self.newDate
self.todo.title = self.newTitle
self.todo.category = self.newCategory
try? self.moc.save()
}
}
}
struct TodoDetailsView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let todo = Todo.init(context: context)
todo.date = Date()
todo.title = "to do item"
return TodoDetailsView(todo: todo).environment(\.managedObjectContext, context)
}
}
The thing I don't know is how to properly group the items by, for example, category.
How to do it using Core Data? I assume I need to change Codegen of my Entity and add an extension to group the records. For example something like this:
let dictionary = Dictionary(grouping: Todo) { $0.category }
But should it be Manual/None or Category/Extension? And where and which code to use? I know how to create a Subclass.
And later I could probably reference to this dictionary in ForEach in my ContentView. But don't know how exactly.
If my assumptions are wrong, please correct me. Thanks in advance.