Episode #228

Let's Build Activity++ - Part 6

Series: Let's Build Activity++!

14 minutes
Published on July 14, 2016

This video is only available to subscribers. Get access to this video and 586 others.

In this episode we allow for generating health data for use in the iOS simulator, where HealthKit data will not be available. We then create some known streaks to make the streak detection and UI decoration easier to test. We end the episode by setting up Quick and Nimble that we will use to test our streak generation algorithm.

Episode Links

Changing the Data source to support HealthKit summaries or ActivityLogs

struct ActivityDataSource {
    private let calendar: NSCalendar
    var activities: [ActivityLog]!

    init(calendar: NSCalendar, summaries: [HKActivitySummary]) {
        self.calendar = calendar
        self.activities = _convert(summaries)
    }

    init(calendar: NSCalendar, activities: [ActivityLog]) {
        self.calendar = calendar
        self.activities = activities
    }

    private func _convert(summaries: [HKActivitySummary]) -> [ActivityLog] {
        return summaries.map { summary in
            return ActivityLog.fromHealthKitSummary(summary, calendar: self.calendar)
            }.sort { (x, y) in return x.date.compare(y.date) == NSComparisonResult.OrderedDescending }

    }
}

Update Random Activity Log Function to influence Streaks

extension ActivityLog {
    static func randomSampleWithDate(date: NSDate, moveCompleted: Bool = false, exerciseCompleted: Bool = false, standCompleted: Bool = false) -> ActivityLog {

        let caloriesBurned = moveCompleted ? 500 : Int(arc4random() % 800)
        let calorieGoal = 500

        let exerciseMin = exerciseCompleted ? 30 : Int(arc4random() % 45)
        let exerciseGoal = 30

        let standHours = standCompleted ? 12 : Int(arc4random() % 16)
        let standGoal = 12

        return ActivityLog(date: date,
                           caloriesBurned: caloriesBurned,
                           activityGoal: calorieGoal,
                           minutesOfExercise: exerciseMin,
                           exerciseGoal: exerciseGoal,
                           standHours: standHours,
                           standGoal: standGoal)
    }
}

Add a Standalone Function to Generate Random Data With Known Streaks

struct FakeHealthData {
    static func randomSampleWithStreaks(calendar calendar: NSCalendar, startingWithDate date: NSDate) -> [ActivityLog] {
        let completedMovementRange: Range<Int> = (1..<5)
        let completedStandingRange: Range<Int> = (3...7)

        let randomSamples: [ActivityLog] = (0..<25).map { i in

            let moveCompleted = completedMovementRange.contains(i)
            let standCompleted = completedStandingRange.contains(i)

            let date = calendar.dateByAddingUnit(.Day, value: -i, toDate: date, options: [])!
            let log = ActivityLog.randomSampleWithDate(date, moveCompleted: moveCompleted, exerciseCompleted: false, standCompleted: standCompleted)
            return log
        }
        return randomSamples
    }
}

Update View Controller to Yield Fake Data on the Simulator

func checkHealthAccess(completion: (Bool, NSError?) -> Void) {

        #if arch(i386) || arch(x86_64)
            completion(true, nil)
        #else
            // request permissions from Healthkit
        #endif
    }

 func loadHealthSamples() {
        #if arch(i386) || arch(x86_64)
            _loadFakeHealthSamples()
        #else
            _loadHealthSamplesFromHealthKit()
        #endif
    }

    func _loadHealthSamplesFromHealthKit() {
        // load from HealthKit
    }

    func _loadFakeHealthSamples() {

        let activities = FakeHealthData.randomSampleWithStreaks(calendar: calendar, startingWithDate: today!)

        self.dataSource = ActivityDataSource(calendar: calendar, activities: activities)
        self.collectionView?.reloadData()
    }

This episode uses Cocoapods 1.0.1, Nimble 4.1.0, Quick 0.9.2, Xcode 7.