Kodeco Forums

CareKit Tutorial for iOS: Part 1

In this 2-part CareKit Tutorial for iOS, learn how easy it is to build an iOS app that helps users manage and understand their personal health.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/929-carekit-tutorial-for-ios-part-1
1 Like

Cool. Thanks! It’s very helpful story

Oh, nice! Really excited to see your CareKit tutorial pop up. Great walk-through and nice touch on the zombie fun. :smiley:

Excellent tutorial! Saved me many many day’s of researching and learning. Thank you!

@eww @instarobot @tilo glad to hear you all found it useful. Thanks for the feedback, it’s really appreciated!

As mentioned these activities are hard coded. Even if I change the data, the app is not updated unless I delete and reinstall. How would one go about changing or adding activities dynamically?

Hi @tilo

You can update the endDate of an activity using setEndDate:forActivity:completion: found in OCKCarePlanStore
http://carekit.org/docs/Classes/OCKCarePlanStore.html

Beyond that, the object is immutable. It makes some sense. If you were to create an activity, and the user completes several associated events, you wouldn’t want to change the activity. For instance, they might have jogged 1 mile every day for a week - and then you change the activity to indicate 2 miles. They’ve suddenly got invalid data from past events.

The correct way to do this is to create a totally new event. You can check if it already exists by looking for it’s UUID, and if it doesn’t, you create it. If for some reason you really need to replace it, you can delete the activity (which removes its associated events) and replace it with a similar one that has your tweaks.

Note the CarePlanStore has a removeActivity:completion: for this purpose.

Hope that helps!

Thank you jeffry, yes. Removing and adding the activity makes sense, and I’ve done that. Except the existing controller still won’t update with the new activity from the store.

        let carePlanManager = CarePlanStoreManager()
        
        carePlanManager.store.remove(breastActivity, completion:                                                       {success , error in
            print ("Trying to remove: error: ", error)
            print ("Trying to remove: success: ", error)
        })
        
        carePlanManager.store.add(breastActivity,completion:
            {success , error in
                print("Adding: Error: ", error)
                print("Adding: Success: ", success)
        })
        
        let viewController = OCKCareCardViewController(carePlanStore: carePlanManager.store)
        
        self.navigationController?.pushViewController(viewController, animated: true)

The new viewController shows the new activity corrrectly. Is there something I should do so the the existing tab bar view controller fetches the new activities in the store manager?

Hi @tilo

I just did a test where I added and removed an activity as you described, and my Care Card did update.

Took another look at your question and I see the issue, if this sample code is pulled from your actual implementation. Here you’ve started by creating a new CarePlanStoreManager, from which you remove and then add the activity.

If you are leveraging the CarePlanStoreManager from ZombieKit, you should change your code to reference CarePlanStoreManager.sharedCarePlanStoreManager. This is a singleton that you can use to maintain a reference to the single OCKCarePlanStore used by the project.

Calling CarePlanStoreManager() directly as you did will basically create a new store over the old one. And since your OCKCareCardViewController is hooked up to the old one (which you passed it when you initialized the controller), it doesn’t see the updates you made.

Let me know if that helps!

Oh dear, I won’t forget to learn this mistake. This worked, thank you jeffro!

Howdy Jeff,

And thanks (very much) for the tutorials. It may be a little late, but could you comment on the design decisions in CareKit? For example, it seems odd that so many closures would require both a “success” parameter and an “error” parameter. Also, it seems strange that the call to the CarePlanStore would pass the retrieved object into a completion closure rather than to the code that is making the call. (The ‘add’ function shows instances of both approaches).

thank you!
Bill

Now I get it!

According to the documentation on Github all calls to the CarePlanStore (other than the call to create the store) are run asynchronously. You have to provide a closure just to get the data back to your app.

Bill

Hi Bill!

So sorry for the delay. I had your original note in my inbox, and things got busy to the point where it dropped off the inbox and my radar.

You are absolutely right about the reason behind the CarePlanStore activity(forIdentifier:completion:) returning the activity in a closure. This way, you can provide code you want to run using the retrieved activity once it comes back.

As for many closures returning both a success and error parameter - this is a fairly common practice in many APIs. While it’s true you could check the error and consider a nil to be success - that’s not a great practice. For instance, a nil return could mean there was a problem processing the return message, and you’d get the opposite result than what was intended.

In the add example, I have a guard up top to confirm the return was successful using success. But as you noticed, I didn’t do anything with the error. In practice, you’d want to throw something inside the else of the guard that does something with the error response. For example, you might pop up an alert telling the user what went wrong. In the case of the tutorial, I was trying to simplify where I could, and so generic error handling didn’t make the cut.

I hope that helps, and thanks for reading the tutorial! If you have other questions, I promise to get back to you in less than a month :]

Jeff

Hello Jeff
Great tutorial!!
I was wondering how would I write assessment for the timed walk test which is part of the active task assessments research kit? This is what I have so far,
public var timedWalk: ORKOrderedTask {
return ORKOrderedTask.timedWalk(withIdentifier: “Timed Walk”, intendedUseDescription: “Assessment measures balance”, distanceInMeters: 3, timeLimit: 13, includeAssistiveDeviceForm: true, options: .excludeConclusion) }
This was written in assessment factory file. How would I write this code so I can implement this into carekit?
thanks

So I was able to get the timed walking test to display on on symptomViewcontroller.
static func timedWalkAssessment() → ORKTask {
return ORKOrderedTask.shortWalk(withIdentifier: “Short Walk Assessment”, intendedUseDescription: “Estimate your fall Risk”, numberOfStepsPerLeg: 20, restDuration: 60, options: .excludeHeartRate)
}
}
Hope this helps

I am getting lots of error while running ZombieKit Part 1 Starter Project, can you please guide me on same?

This tutorial is more than six months old so questions are no longer supported at the moment for it. We will update it as soon as possible. Thank you! :]