Apple Health Frameworks

Nov 29 2022 · Swift 5, iOS 15, Xcode 13

Part 2: Dive Into More Details

09. Work With StoreManager

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 08. Create a CheckIn Task Next episode: 10. Make a Follow-Up Vaccination Task

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 09. Work With StoreManager

Part 2, Episode 10, Work with StoreManager

In this episode, I want to show you how to work with CareKitStore using StoreManager. Until now, you had the StoreManager on the memory, which means every time you opened the app, it was empty, but from now on, I want to tell you how to store it on the disk, so you don’t need it to do the onboarding task again and again.

Open SceneDelegate from project navigator and change the type of StoreManager from .inMemory to:

      type: .onDisk(protection: .none)

Here you saved the StoreManager on the disk, but make sure you put proper protection on the production apps. Build and run the app and follow the tasks up to the CheckIn. Now stop the build and open the app again to see you have already done all the tasks.

Let’s look at some illustrations from Apple; here is the scheme of the StoreManager from high level pov.

Patient: A patient represents the user of the app.

Care Plan: A patient may have zero or more care plans. A care plan organizes the contacts and tasks associated with a specific treatment.

Contact: A care plan may have zero or more associated contacts. Contacts might include doctors, nurses, insurance providers, or family.

Task: A care plan may have zero or more tasks. A task represents some activity that the patient is supposed to perform.

Schedule: Each task must have a schedule. The schedule defines occurrences of a task and may optionally specify target or goal values.

Outcome: Each task occurrence may or may not have an associated outcome.

Outcome Value: Each outcome may have zero or more values associated with it. A value might represent how much medication was taken, or a plurality of outcome values could represent the answers to a survey.

Let’s jump back to the code and open TaskViewController; until now, you first show the onboarding task, then check if it was completed, show the vaccination task, then the CheckIn, and you did disable the future ones, but what if the user goes back and try something from the past. Build and run the project and try out something from the past.

Yeah, it crashes the app. The issue here is there is no associated task for that date. The next step is to fix that issue by fetching the tasks by date and then showing the related viewController in the TaskViewController.

Open TaskViewModel from project navigator and add this function right after // Fetch tasks by date comment at the bottom of the class:

static func fetchTasks(on date: Date, storeManager: OCKSynchronizedStoreManager, completion: @escaping([OCKAnyTask]) -> Void) {
    var query = OCKTaskQuery(for: date)
    query.excludesTasksWithNoEvents = true

    storeManager.store.fetchAnyTasks(
      query: query,
      callbackQueue: .main) { result in
      switch result {
      case .failure:
        Logger.task.error("Failed to fetch tasks for date \(date)")
        completion([])
      case let .success(tasks):
        completion(tasks)
      }
    }
  }

Here, you make an OCKTaskQuery by inputting the date and then fetching any tasks for that query and returning the result as OCKAnyTask in an array.

Now open TaskViewController, change the existing code, and use that fetchTask function right after // Fetch tasks by date comment.

TaskViewModel.fetchTasks(on: date, storeManager: self.storeManager) { tasks in
            tasks.forEach {
              guard let id = TaskModel(rawValue: $0.id) else { return }
              if id == TaskModel.checkIn {
                TaskViewModel.makeTaskViewController(
                  input: id,
                  date: date,
                  storeManager: self.storeManager,
                  listViewController: listViewController,
                  delegate: self)
              }
            }
          }

You now fetch all the tasks from the storemanager and then check if it’s CheckIn then, you show the related TaskViewController. Build and run the app to see now that there is no task in the past.