carekit-apple / CareKit

CareKit is an open source software framework for creating apps that help people better understand and manage their health.
https://www.researchandcare.org
Other
2.4k stars 443 forks source link

Changing OCKStore ID When Trying to Add/Delete tasks #445

Open MihirJoe opened 4 years ago

MihirJoe commented 4 years ago

Hello,

Whenever I want to add/delete a task or change text in a task in my OCKStore, I'm not able to see any change unless I change the OCKStore ID. However, when this happens, it creates a new store and all of the previously logged information is gone. Is there any way to keep one care plan store identification and still change up the tasks?

I'm using a separate NSObject to handle the store and I use a function inside of an extension of OCKStore to create all of the tasks I need called 'populateSampleData()'.

`let store = OCKStore(name: "MyCarePlanStore", type: .onDisk)

static let sharedCarePlanStoreManager = Manager()

override init() {
  let fileManager = FileManager.default
  guard let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).last else {
    fatalError("Failed to obtain Documents directory!")
  }

  let storeURL = documentDirectory.appendingPathComponent("MyCarePlanStore")

  if !fileManager.fileExists(atPath: storeURL.path) {
    try! fileManager.createDirectory(at: storeURL, withIntermediateDirectories: true, attributes: nil)
  }

    store.populateSampleData()

  super.init()

}

}`

erik-apple commented 4 years ago

You should be able to use just one store, without changing its name. CareKit already performs the checks that you've put in place in your initializer, but it puts the store in NSPersistentContainer.defaultDirectoryURL, which may not be where you are checking. I recommend removing those checks and leaving it up to CareKit.

I suspect that the reason you're not seeing any changes is because you're using an .onDisk store. The first time you run your app, it will insert the sample data into the store. The second time you run your app, it will attempt to put the data into the store, but see that tasks with the same id already exist, and then fail to add the new version of the task.

You can confirm this by checking for errors in the completion block of the methods inside of populateSampleData().

The typical solution to this is to use an .inMemory store while developing, and then switch to an .onDisk store once you're happy with your seed data.

MihirJoe commented 4 years ago

Thanks for the quick response! I tried out the .inMemory and have changed a few tasks around, but when I change the store back to .onDisk, I get this error:

Screen Shot 2020-06-06 at 1 34 20 PM

Because it's stopping at the dateInterval line, I went back to my store manager, and looked at this line that's responsible for setting the date for an OCKSchedule:

let doseTime = OCKSchedule.dailyAtTime(hour: hour!, minutes: minutes!, start: date, end: nil, text: "Make sure you're on a full stomach.", duration: .allDay, targetValues: [])

The part with the start date has remained the same and I played around with it a bit, but I eventually concluded that Xcode is trying to unwrap an optional value. I'm not entirely sure if this is the right diagnosis of the problem, but it's strange because this wasn't really changed after I started using .inMemory.

In terms of checking for errors in the completion, what would you recommend I implement to do so. Would I add it to this line in my populateSampleData() funciton?

addTasks([skinSymptoms, peanutDose, oralSymptoms, giSymptoms, anaphylaxis], callbackQueue: .main, completion: nil)

MihirJoe commented 4 years ago

Additionally, I've been struggling with trying to retrieve the insights from a bar chart that I have. My goal is to create a report of a graph for each week and send be able to share that with the physician. I know I opened an issue in here back in April about converting to PDF, but I'm looking to get the raw data from the insights charts. I know that CareKit utilizes CoreData to store patient data locally, but I'm not sure how to access that; I'm not too familiar with using CoreData.

erik-apple commented 4 years ago

Can you provide information about the tasks you're using? It seems like there may be something about the versioning of those tasks that CareKit doesn't know how to handle gracefully.

Yes, to check for errors when adding tasks, you would use the completion block, which is nil in the snippet you provided.

addTasks(
    [skinSymptoms, peanutDose, oralSymptoms, giSymptoms, anaphylaxis],
    callbackQueue: .main,
    completion: { result in

    switch result {
    case let .failure(error):
        print(error)
    case let .success(tasks):
        print("Successfully added \(tasks.count) tasks!")
 })
MihirJoe commented 4 years ago

Sure! Here's the data I'm trying to populate the store with:

` let startDate = Calendar.current.startOfDay(for: Date())

    let date = Date()

    let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: date)
    let hour = dateComponents.hour
    let minutes = dateComponents.minute

    let doseTime = OCKSchedule.dailyAtTime(hour: hour!, minutes: minutes!, start: date, end: nil, text: "Make sure you're on a full stomach.", duration: .allDay, targetValues: [])

     var peanutDose = OCKTask(id: "peanutDose", title: "Take OIT Dose",
                               carePlanID: nil, schedule: doseTime)

       peanutDose.instructions = "Keep a resting heart rate for the next 2 hours."

       let skinSymptomsSchedule = OCKSchedule(composing: [
           OCKScheduleElement(start: startDate, end: nil, interval: DateComponents(day: 1),
                              text: "Anytime throughout the day", targetValues: [], duration: .allDay)
           ])

       var skinSymptoms = OCKTask(id: "itching", title: "Experiencing Any Skin Irrations?",
                            carePlanID: nil, schedule: skinSymptomsSchedule)
       skinSymptoms.impactsAdherence = false
       skinSymptoms.instructions = "These include itching and rashes/hives."

    var giSymptoms = OCKTask(id: "giSymptoms", title: "Experiencing any GI Problems?", carePlanID: nil, schedule: skinSymptomsSchedule)
    giSymptoms.impactsAdherence = false
    giSymptoms.instructions = "These include reflux, nausea, pain, and/or vomiting."

    var oralSymptoms = OCKTask(id: "oralSymptoms", title: "Experiencing Any Oral Issues?", carePlanID: nil, schedule: skinSymptomsSchedule)
    oralSymptoms.impactsAdherence = false
    oralSymptoms.instructions = "These include itching and/or swelling of your mouth and lips."

    var anaphylaxis = OCKTask(id: "anaphylaxis", title: "Having a reaction? ", carePlanID: nil, schedule: skinSymptomsSchedule)
    anaphylaxis.impactsAdherence = false
    anaphylaxis.instructions = "Tap the button below if you experience an allergic reaction."

    addTasks([skinSymptoms, peanutDose, oralSymptoms, giSymptoms, anaphylaxis], callbackQueue: .main, completion: nil)

`

erik-apple commented 4 years ago

@MihirJoe It looks like you've got an older version of the framework checked out, and there was a bug similar to the one you're seeing a few months ago. I'd suggest pulling a more recent commit. It's likely that this has already been fixed. I tried adding the same tasks to an .onDisk store on a recent commit I didn't hit any crashes!