rcasanovan / iHealth

A simple iOS app to integrate HealthKit to show some info for the user
Apache License 2.0
8 stars 0 forks source link
cocoapods codable decodable healthkit json protocol realm realm-database swift viper viper-architecture viper-pattern-architecture

iHealth

This is a simple iOS app to integrate HealthKit to show some info for the user

🚨 Important note 🚨

This project is using cocoapods. Please be sure to run the pod install command before running the project.

If you have any doubt about cocoapods you can check the reference here.

Cool things with the demo

Project Architecture

alt tag

References:

How did I implement VIPER?

Basically I have a protocol file for each scene in the app. This file defines the interaction between each layer as following:

Whith this protocols file is really easy to know how each layer notify / request / information to the other ones so we don't have any other way to communicate all the layers.

Another important point is because I'm using protocols it's really easy to define mocks views / presenters / interactors / routers for testing.

// View / Presenter
protocol GoalsViewInjection : class {
    func showProgress(_ show: Bool, status: String)
    func showProgress(_ show: Bool)
    func showMessageWith(title: String, message: String, actionTitle: String)
    func loadGoals(_ viewModels: [GoalViewModel])
}

protocol GoalsPresenterDelegate : class {
    func viewDidLoad()
    func refresh()
}

// Presenter / Interactor

typealias GoalsGetGoalsCompletionBlock = (_ viewModel: [GoalViewModel]?, _ success: Bool, _ error: ResultError?) -> Void

protocol GoalsInteractorDelegate : class {
    func getGoalsList(completion: @escaping GoalsGetGoalsCompletionBlock)
    func clear()
}

First at all. Where is the data came from?

I'm using the following endpoint to get the goals list -> https://thebigachallenge.appspot.com/_ah/api/myApi/v1/goals/.

Data models

Network data models

public struct GoalsResponse: Decodable {

    let items: [GoalResponse]

}

public struct GoalResponse: Decodable {

    let id: String
    let title: String
    let description: String
    let type: String
    let goal: Int
    let reward: RewardResponse

}

public struct RewardResponse: Decodable {

    let trophy: String
    let points: Int

}

I'm using a Swift Standard Library decodable functionality in order to manage a type that can decode itself from an external representation (I really ❤ this from Swift).

Reference: Apple documentation

Local goals data model

This model is used for the local goals

class LocalGoal: Object {

    @objc dynamic var goalId: String?
    @objc dynamic var title: String = ""
    @objc dynamic var goalDescription: String = ""
    @objc dynamic var type: String = ""
    @objc dynamic var goal: Int = 0
    @objc dynamic var trophy: String = ""
    @objc dynamic var points: Int = 0

    override class func primaryKey() -> String? {
        return "goalId"
    }

}

As I'm using Realm for this it's important to define a class to manage each model in the database. In this case we only have one model (LocalGoal)

Reference: Realm

Managers

I think using managers is a good idea but be careful!. Please don't create managers as if the world were going to end tomorrow.

I'm using only 4 here:

ShareManager

Used to share the current progress using UIActivityViewController.

ReachabilityManager

Used to manage the reachability. In this case I would like to notify a little issue related with the simulator. It seems Xcode has an issue with the simulator because if you try to turn off the wifi and turning on again, the observer for the state change is not triggering. It's working 100% fine in a real device.

LocalGoalManager

Used to save the goals locally using a Realm database.

HealthManager

Used to manage all the connections and requests with the HealthKit framework.

How it looks like?

General goals and my personal goals

alt tag alt tag

Share option && permission request

alt tag alt tag

No internet connection screen

alt tag

What's left in the demo?

Programming languages && Development tools

Third-Party Libraries

Support && contact

Email

You can contact me using my email: ricardo.casanova@outlook.com

Twitter

Follow me @rcasanovan on twitter.