Initialzing a custom binding w/ Core Data - core-data

So far my only use of CoreData has been with lists and using fetch requests to populate them.
Well how would I go about saving one Bool as true or false for a view?
The bool will be used to fill a ⭐️
My idea is to pass a function I have on my CoreData class
static func isFavoritedCheck(using movieID: Int, context: NSManagedObjectContext) -> Bool {
let model = MovieData(context: context)
return movieID == model.movieID && model.favorite == true
}
To the custom binding in the view.. Is this possible or is using a FetchRequest the only way?
struct StarView: View {
#Binding var favorited: Bool
let movieID: Int
let storage: StorageProvider
init(movieID: Int, storage: StorageProvider) {
self.movieID = movieID
self.storage = storage
_favorited = Binding //stuck here
}

Yes, it is possible, like this, you need wrap it as Binding!
struct StarView: View {
let movieID: Int
let storage: StorageProvider
#Binding var favorited: Bool
init(movieID: Int, storage: StorageProvider, favorited: Binding<Bool>) {
self.movieID = movieID
self.storage = storage
_favorited = favorited
}
var body: some View {
//. . .
}
}

Related

How to use a function in another swift file that contains CoreData related properties?

clueless beginner here. Apologies if my question is formed poorly. This is the first time I ask a question of this scale and I have a hard time balancing between posting too much code for the good samaritans to read and too little to post an effective question. Huge thanks in advance!
I am trying to incorporate the textfieldalert in this post in my learner project. There are two Swift files in questions: File A (PosTextFieldAlertView) has an extension that needs to use two functions in File B (ListView).
These are the functions I need to use in File A.
func addPositive(){
let newPositive = PositiveEntity(context: viewContext)
newPositive.title = alertInput
save()
}
func save() {
do { try viewContext.save() } catch { print(error) }
}
I thought of/researched two methods: 1) duplicate the function in File A or 2) create instance of the view in File B that contains that functions according this post. However I ran into problems in both methods.
Duplicating the functions:
I copied the CoreData related properties in the PosTextFieldAlert struct. But now PosTextFieldAlert in the return part of the extension has the error of "Missing arguments for parameters [Core Data properties] in call". I don’t know how to set the property in the extension without referring or creating a different sets of Core Data entities.
Creating an instance of the relevant view
In the instance creation I would need to input the arguments but I don’t know how to refer to the same NSManagedObjectContext.
Code excerpts:
PosTextFieldAlertView
struct PosTextFieldAlert<Presenting>: View where Presenting: View {
var viewContext: NSManagedObjectContext
var positives: [PositiveEntity]
var targets: [TargetEntity]
#State private var alertInput = ""
// let listView = ListView(viewContext: NSManagedObjectContext, positives: PositiveEntity, negatives: NegativeEntity, targets: TargetEntity)
#Binding var isShowing: Bool
#Binding var text: String
let presenting: Presenting
let title: String
var body: some View {
GeometryReader { (deviceSize: GeometryProxy) in
ZStack {
self.presenting
.disabled(isShowing)
VStack {
Text(self.title)
TextField(self.title, text: self.$text)
Divider()
VStack{
HStack {
Button(action: {
withAnimation {
self.isShowing.toggle()
}
}) {
Text("+")
}.padding()
Button(action: {
withAnimation {
self.isShowing.toggle()
}
}) {
Text("-")
}.padding()
}
Button(action: {
withAnimation {
self.isShowing.toggle()
}
}) {
Text("Done")
}
}
}
.padding()
.background(Color.white)
.frame(
width: deviceSize.size.width*0.7,
height: deviceSize.size.height*0.7
)
.shadow(radius: 1)
.opacity(self.isShowing ? 1 : 0)
}
}
}
func addPositive(){
let newPositive = PositiveEntity(context: viewContext)
newPositive.title = alertInput
save()
}
func save() {
do { try viewContext.save() } catch { print(error) }
}
}
extension View {
func posTextFieldAlert(isShowing: Binding<Bool>,
text: Binding<String>,
title: String) -> some View {
PosTextFieldAlert(isShowing: isShowing,
text: text,
presenting: self,
title: title)
}
}
The code in ListView
struct ListView: View {
var viewContext: NSManagedObjectContext
var positives: [PositiveEntity]
var negatives: [NegativeEntity]
var targets: [TargetEntity]
//[layout of the project]
}
The Fetchrequests in ContentView:
#Environment(\.managedObjectContext) var viewContext
#FetchRequest(sortDescriptors: []) var targets: FetchedResults<TargetEntity>
#FetchRequest(sortDescriptors: []) var positives: FetchedResults<PositiveEntity>
#FetchRequest(sortDescriptors: []) var negatives: FetchedResults<NegativeEntity>

SwiftUI ForEach force UI update when updating the contents of a core data relationship

My app is meant to have a bunch of workouts in core data, each with a relationship to many exercises. A view should display the data in each workout (name, description etc.) and then iterate and display each exercise belonging to that workout.
Adding exercises and displaying them works fine. If an exercise is deleted, however it:
deletes from coredata no worries
the information seems to delete from iterableExercises
however, the Text line does not disappear. it goes from, for example "Squat, Description" to simply " , "
If I close the app entirely and reopen, then the " , " lines do completely disappear.
The problem code:
if let iterableExercises = workout.exercises?.array as? [ExerciseEntity] {
ForEach(iterableExercises) {exercise in
Text("\(exercise.name ?? ""), \(exercise.desc ?? "")")
}
}
I've got the entity relationship set as ordered, but I've also tried unordered with .allObjects instead of .array. This clearly isn't the problem as it's the array iterableExercises that's not correctly being reset?
EDIT: to reproduce, here's all the code you need and some screenshots of the CoreData model.
import SwiftUI
import CoreData
class ViewModel: ObservableObject {
let container: NSPersistentCloudKitContainer
#Published var savedWorkouts: [WorkoutEntity] = []
#Published var savedExercises: [ExerciseEntity] = []
// MARK: INIT
init() {
container = NSPersistentCloudKitContainer(name: "mre")
container.loadPersistentStores { description, error in
if let error = error {
print("Error loading CoreData: \(error)")
}
}
fetchWorkoutEntities()
fetchExerciseEntities()
}
// MARK: FETCHERS
func fetchWorkoutEntities() {
let request = NSFetchRequest<WorkoutEntity>(entityName: "WorkoutEntity")
do {
savedWorkouts = try container.viewContext.fetch(request)
} catch let error {
print("Error fetching WorkoutEntity: \(error)")
}
}
func fetchExerciseEntities() {
let request = NSFetchRequest<ExerciseEntity>(entityName: "ExerciseEntity")
do {
savedExercises = try container.viewContext.fetch(request)
} catch let error {
print("Error fetching ExerciseEntity: \(error)")
}
}
// MARK: SAVE
func saveData() {
do {
try container.viewContext.save()
fetchWorkoutEntities()
fetchExerciseEntities()
} catch let error {
print("Error saving: \(error)")
}
}
// MARK: ADDERS
func addWorkout(name: String) {
let _ = WorkoutEntity(context: container.viewContext)
saveData()
}
func addExerciseToWorkout(workout: WorkoutEntity, name: String) {
let newExercise = ExerciseEntity(context: container.viewContext)
newExercise.name = name
workout.addToExercises(newExercise)
saveData()
}
// MARK: DELETERS
func deleteWorkout(workout: WorkoutEntity) {
container.viewContext.delete(workout)
saveData()
}
func deleteExercise(exercise: ExerciseEntity) {
container.viewContext.delete(exercise)
saveData()
}
// MARK: TODO: UPDATERS
}
struct ContentView: View {
#StateObject var data = ViewModel()
var body: some View {
VStack {
Button {
data.addWorkout(name: "workout")
data.addExerciseToWorkout(workout: data.savedWorkouts[0], name: "[exercisename]")
} label: {
Text("Click ONCE to add workout to work with")
}
Spacer()
if let iterableExercises = data.savedWorkouts[0].exercises?.array as? [ExerciseEntity] {
ForEach(iterableExercises) { exercise in
Button {
data.deleteExercise(exercise: exercise)
} label: {
Text("Click to delete \(exercise.name ?? "") AFTER DELETING IF THIS STILL SHOWS BUT DOESN'T SHOW THE EXERCISE NAME THEN IT'S BROKEN")
}
}
}
Spacer()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
screenshots of model
I’m not sure if this is the ONLY solution as #malhal gave quite an extensive and seemingly useful response.
But I came across a much easier and immediate fix, within my original solution. The inverse relationships must be specified. Doing this resolved all issues.
We don't use view model objects in SwiftUI. You need to learn the View struct and property wrappers which gives the consistency and efficiency of value types with the benefits of reference types. The property wrapper for core data is #FetchRequest which invalidates the View when the results change. It's also a DynamicProperty (which is how it gets the context from the environment) that you can use it directly without the property wrapper syntax which allows you to use a param in a predicate, in your case to do fetch the one-to-many relation, e.g.
struct WorkoutView: View {
private var fetchRequest: FetchRequest<Exercise>
private var exercices: FetchedResults<Exercise> {
fetchRequest.wrappedValue
}
init(workout: Workout) {
let sortAscending = true
let sortDescriptors = [SortDescriptor(\Exercise.timestamp, order: sortAscending ? .forward : .reverse)]
fetchRequest = FetchRequest(sortDescriptors: sortDescriptors, predicate: NSPredicate(format: "workout = %#", workout), animation: .default)
}
var body: some View {
List(exercises) { exercise in
ExerciseView(exercise: exercise)
}
}
}
For creating the NSPersistentContainer check out the Xcode App template with Core Data checked. Looks like this:
#main
struct TestApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
The reason it is not an #StateObject is we don't want to invalidate this body when it changes and we need it to be init for previewing which is a different singleton.
struct PersistenceController {
static let shared = PersistenceController()
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
... see template
That other code in your view model class can be moved to NSManagedObject and NSManagedObjectContext extensions. Use the Editor menu to generate the NSManagedObject extension for the model, the files need tidying up though and make sure use extension is selected for the entity.

How to use a picker on CoreData relationships in SwiftUI

G'day everyone,
I'm trying to work out how CoreData relationships can work with UI elements like pickers.
At the moment I have a 3 view app (based on the Xcode boilerplate code) which displays a list of parent entities, which have children which have children. I want a picker to select which grandchild a child entity should refer to.
At the moment I have two funny side effects:
When I run the app as a preview (so there is pre-populated data... this sample code will break without the data in place),
the selected grandchild in the picker is the grandchild of the first
child, irrespective of which child you're dropped into in the first
view.
When I drop back and pick another child, now the picked grabs the correct initial selection from the child entity
When I select a child and "save" that, the value in the child summary does not change, until I click another child at which point the value changes before the transition to the modal view.
I am clearly missing something in my understanding of the sequence of events when presenting modals in SwiftUI... can any what shed any light on what I've done wrong?
Here's a video to make this more clear:
https://github.com/andrewjdavison/Test31/blob/main/Test31%20-%20first%20click%20issue.mov?raw=true
Git repository of the sample is https://github.com/andrewjdavison/Test31.git, but in summary:
Data Model:
View Source:
import SwiftUI
import CoreData
struct LicenceView : View {
#Environment(\.managedObjectContext) private var viewContext
#Binding var licence: Licence
#Binding var showModal: Bool
#State var selectedElement: Element
#FetchRequest private var elements: FetchedResults<Element>
init(currentLicence: Binding<Licence>, showModal: Binding<Bool>, context: NSManagedObjectContext) {
self._licence = currentLicence
self._showModal = showModal
let fetchRequest: NSFetchRequest<Element> = Element.fetchRequest()
fetchRequest.sortDescriptors = []
self._elements = FetchRequest(fetchRequest: fetchRequest)
_selectedElement = State(initialValue: currentLicence.wrappedValue.licenced!)
}
func save() {
licence.licenced = selectedElement
try! viewContext.save()
showModal = false
}
var body: some View {
VStack {
Button(action: {showModal = false}) {
Text("Close")
}
Picker(selection: $selectedElement, label: Text("Element")) {
ForEach(elements, id: \.self) { element in
Text("\(element.desc!)")
}
}
Text("Selected: \(selectedElement.desc!)")
Button(action: {save()}) {
Text("Save")
}
}
}
}
struct RegisterView : View {
#Environment(\.managedObjectContext) private var viewContext
#State var showModal: Bool = false
var currentRegister: Register
#State var currentLicence: Licence
init(currentRegister: Register) {
currentLicence = Array(currentRegister.licencedUsers! as! Set<Licence>)[0]
self.currentRegister = currentRegister
}
var body: some View {
VStack {
List {
ForEach (Array(currentRegister.licencedUsers! as! Set<Licence>), id: \.self) { licence in
Button(action: {currentLicence = licence; showModal = true}) {
HStack {
Text("\(licence.leasee!) : ")
Text("\(licence.licenced!.desc!)")
}
}
}
}
}
.sheet(isPresented: $showModal) {
LicenceView(currentLicence: $currentLicence, showModal: $showModal, context: viewContext )
}
}
}
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Register.id, ascending: true)],
animation: .default)
private var registers: FetchedResults<Register>
var body: some View {
NavigationView {
List {
ForEach(registers) { register in
NavigationLink(destination: RegisterView(currentRegister: register)) {
Text("Register id \(register.id!)")
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
[1]: https://i.stack.imgur.com/AfaNb.png
I didn't really understand this
• selected grandchild in the picker is the grandchild of the first child, irrespective of which child you're dropped into in the first view.
• When I drop back and pick another child, now the picked grabs the correct initial selection from the child entity
Could you attach a video that represents a problem?
But I can give you a solution to the preview problem and the second one.
Preview
If you use preview with Core Data, you need to use a viewContextcreated with MockData and pass it to your View. Here I provide a generic code, that can be modified for each of your views:
In your Persistance struct (CoreData Manager) declare a variable preview with your preview Items:
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
// Here you create your Mock Data
let newItem = Item(context: viewContext)
newItem.yourProperty = yourValue
do {
try viewContext.save()
} catch {
// error handling
}
return result
}()
Make sure it has inMemory: Bool in its init, as it is responsible for separating real viewContext and previewContext:
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "TestCD")
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)")
}
})
}
Create Mock Item from your viewContext and pass it to preview:
struct YourView_Previews: PreviewProvider {
static var previews: some View {
let context = PersistenceController.preview.container.viewContext
let request: NSFetchRequest<Item> = Item.fetchRequest()
let fetchedItems = try! context.fetch(request)
YourView(item: fetchedItems)
}
}
If you use #FetchRequest and #FetchedResults it makes it easier, as they will do creating and fetching objects for you. Just implement a preview like this:
struct YourView_Previews: PreviewProvider {
static var previews: some View {
YourView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
Here is Persistence struct created by Xcode at the moment of the project initialization:
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
let item = Item(context: viewContext)
item.property = yourProperty
do {
try viewContext.save()
} catch {
}
return result
}()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "TestCD")
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)")
}
})
}
}
Second problem
Core Data objects are built with classes, so their type is a reference. When you change a property is a class it doesn't notifiy the view struct to redraw with a new value. (exception is classes, that are created to notify about changes.)
You need to explicitly tell your RegisterView struct to redraw itself after you dismiss your LicenceView. You can do it by creating one more variable in your RegisterView - #State var id = UUID(). Then attach an .id(id) modifier at the end of your VStack
VStack {
//your code
}.id(id)
Finally, create a function viewDismissed which will change the id property in your struct:
func viewDismissed() {
id = UUID()
}
Now, attach this function to your sheet with an optional parameter onDismiss
.sheet(isPresented: $showModal, onDismiss: viewDismissed) {
LicenceView(currentLicence: $currentLicence, showModal: $showModal, context: viewContext )
}
OK. Huge vote of thanks to Lorem for getting me to the answer. Thanks too for Roma, but it does turn out that his solution, whilst it worked to resolve one of my key problems, does introduce inefficiencies - and didn't resolve the second one.
If others are hitting the same issue I'll leave the Github repo up, but the crux of it all was that #State shouldn't be used when you're sharing CoreData objects around. #ObservedObject is the way to go here.
So the resolution to the problems I encountered were:
Use #ObservedObject instead of #State for passing around the CoreData objects
Make sure that the picker has a tag defined. The documentation I head read implied that this gets generated automatically if you use ".self" as the id for the objects in ForEach, but it seems this is not always reliable. so adding ".tag(element as Element?)" to my picker helped here.
Note: It needed to be an optional type because CoreData makes all the attribute types optional.
Those two alone fixed the problems.
The revised "LicenceView" struct is here, but the whole solution is in the repo.
Cheers!
struct LicenceView : View {
#Environment(\.managedObjectContext) private var viewContext
#ObservedObject var licence: Licence
#Binding var showModal: Bool
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Element.desc, ascending: true)],
animation: .default)
private var elements: FetchedResults<Element>
func save() {
try! viewContext.save()
showModal = false
}
var body: some View {
VStack {
Button(action: {showModal = false}) {
Text("Close")
}
Picker(selection: $licence.licenced, label: Text("Element")) {
ForEach(elements, id: \.self) { element in
Text("\(element.desc!)")
.tag(element as Element?)
}
}
Text("Selected: \(licence.licenced!.desc!)")
Button(action: {save()}) {
Text("Save")
}
}
}
}

Count core data attributes that fulfill a certain condition (SwiftUI)

I have created a core data entity with the following attributes (from Item+CoreDataProperties.swift file):
extension Item {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Item> {
return NSFetchRequest<Item>(entityName: "Item")
}
#NSManaged public var id: UUID?
#NSManaged public var likes: Int16
}
I am trying to return within ContentView a variable that shows the total number of Item that have more than 5 likes. What would be the best way to do this?
I've tried adding the following computed property, but it only checks whether the first item in the array fulfills the condition and I I'm not sure how to get it to loop over all of them.
#FetchRequest(entity: Item.entity(), sortDescriptors: [])
var item: FetchedResults<Item>
var likesCount:Int {
get {
if item[0].likes > 5 {
return 1
}
else {
return 0
}
}
}
I was also reading about a method called countForFetchRequest, but it seems to only be for detecting errors and I'm not sure it applies here.
Many thanks! Any help greatly appreciated.
Maybe something like this:
var countOfItems: Int {
getCount()
}
and then:
func getCount() -> Int {
var countOfItems: Int = 0
let context = PersistenceController.shared.container.viewContext
let itemFetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
itemFetchRequest.predicate = NSPredicate(format: "likes > %d", 5)
do {
countOfItems = try context.count(for: itemFetchRequest)
print (countOfItems)
}
catch {
print (error)
}
return countOfItems
}

How to use fetch data in Intent Handler for editing Widget iOS 14?

I'm currently developing an application using SwiftUI.
I'm trying to make a widget user can edit some data using IntentConfiguration
I want to use some fetch data from CoreData in IntentHandler class for editing the widget like the image below.
I tried to make some codes but They don't work...
How could I solve my codes?
Here are the codes:
IntentHandler.swift
import WidgetKit
import SwiftUI
import CoreData
import Intents
class IntentHandler: INExtension, ConfigurationIntentHandling {
var moc = PersistenceController.shared.managedObjectContext
var timerEntity_0:TimerEntity?
var timerEntity_1:TimerEntity?
var timerEntity_2:TimerEntity?
init(context : NSManagedObjectContext) {
self.moc = context
let request = NSFetchRequest<TimerEntity>(entityName: "TimerEntity")
do{
let result = try moc.fetch(request)
timerEntity_0 = result[0]
timerEntity_1 = result[1]
timerEntity_2 = result[2]
}
catch let error as NSError{
print("Could not fetch.\(error.userInfo)")
}
}
func provideNameOptionsCollection(for intent: ConfigurationIntent, searchTerm: String?, with completion: #escaping (INObjectCollection<NSString>?, Error?) -> Void) {
let nameIdentifiers:[NSString] = [
NSString(string: timerEntity_0?.task ?? "default"),
NSString(string: timerEntity_1?.task ?? "default"),
NSString(string: timerEntity_2?.task ?? "default")
// "meeting",
// "cooking",
// "shoping"
]
let allNameIdentifiers = INObjectCollection(items: nameIdentifiers)
completion(allNameIdentifiers,nil)
}
override func handler(for intent: INIntent) -> Any {
return self
}
}
Widget.swift
import WidgetKit
import SwiftUI
import Intents
struct Provider: IntentTimelineProvider {
typealias Intent = ConfigurationIntent
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), configuration: ConfigurationIntent(), name: "")
}
func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: #escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), configuration: configuration, name: "")
completion(entry)
}
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, configuration: configuration, name: configuration.Name ?? "")
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationIntent
var name:String
}
struct TimerIntentWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
Text(entry.name)
.font(.title)
Text(entry.date, style: .time)
}
}
#main
struct TimerIntentWidget: Widget {
let kind: String = "TimerIntentWidget"
var body: some WidgetConfiguration {
IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in
TimerIntentWidgetEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
tWidget.intentdefinition
Xcode: Version 12.0.1
iOS: 14.0
Life Cycle: SwiftUI App
I could display a list in the widget using fetch data from CoreData like the code below:
IntentHandler.swift
import WidgetKit
import SwiftUI
import CoreData
import Intents
class IntentHandler: INExtension, ConfigurationIntentHandling {
var moc = PersistenceController.shared.managedObjectContext
var timerEntity_0:TimerEntity?
var timerEntity_1:TimerEntity?
var timerEntity_2:TimerEntity?
func provideNameOptionsCollection(for intent: ConfigurationIntent, searchTerm: String?, with completion: #escaping (INObjectCollection<NSString>?, Error?) -> Void) {
let request = NSFetchRequest<TimerEntity>(entityName: "TimerEntity")
do{
let result = try moc.fetch(request)
timerEntity_0 = result[0]
timerEntity_1 = result[1]
timerEntity_2 = result[2]
}
catch let error as NSError{
print("Could not fetch.\(error.userInfo)")
}
let nameIdentifiers:[NSString] = [
NSString(string: timerEntity_0?.task ?? "default"),
NSString(string: timerEntity_1?.task ?? "default"),
NSString(string: timerEntity_2?.task ?? "default")
// "meeting",
// "cooking",
// "shoping"
]
let allNameIdentifiers = INObjectCollection(items: nameIdentifiers)
completion(allNameIdentifiers,nil)
}
override func handler(for intent: INIntent) -> Any {
return self
}
}

Resources