Search code examples
iosswiftparse-platformlocal-datastore

Parse Local Datastore + Network Sync


I am using Parse.com with my iOS application (written in Swift) since 6 month and I would like to use Parse local Datastore for many reasons :

  • Make my application usable (retrievable) offline
  • Reduce data usage (many queries returning « non updated data »)
  • Reduce loading time (mainly when starting application and loading all data from network)

In order to do so I would like to write a global function handeling these scenarios for all the query I do from my application.

I already have a specific idea of what the function should do but I don’t know how to technically write this function :)

Scenarios :

  • Sign Up / Log In (chain multiple query) :

    1. Get data from Network
    2. Save date inside « lastUpdateLocalDatastore » variable in NSUserDefaults
    3. Pin data in Local Datastore
    4. Display data from Local Datastore —> RETURN & update TableView
  • Loading App (chain multiple query) :

    1. Display data from Local Datastore —> RETURN & update TableView
    2. Get data from Network (where « lastUpdateDate » in Parse is newer than « lastUpdateLocalDatastore » from NSUserDefault)
    3. Pin data in Local Datastore
    4. Display updated data from Local Datastore —> RETURN & update TableView
  • Trigger update (simple query) :

    1. Get data from Network (where « lastUpdateDate » in Parse is newer than « lastUpdateLocalDatastore » from NSUserDefault)
    2. Pin data in Local Datastore
    3. Display updated data from Local Datastore —> RETURN & update TableView
  • Log Out :

    1. Unpin all data in Local Datastore
    2. Clear « lastUpdate » values in NSUserDefault

Function structure :

IF ( "First login" -> Local Datastore is empty ) {

    Get data from Network
    Pin data in Local Datastore
    Save « lastUpdateLocalDatastore » in NSUSerDefaults
    —> RETURN data in Cache

} ELSE {

    IF ( "Launching application" -> Cache is empty ) {
        Get data from Local Datastore
        —> RETURN data in Cache
    } ELSE IF ( "trigger update" ) {
       Get data from Network
       Pin new data in Local Datastore
       Save « lastUpdateLocalDatastore » in NSUSerDefaults
       —> RETURN data in Cache
    }
}

Problems :

  1. How to handle multiple (asynchronous) returns
  2. How to make a function capable of chaining multiple queries (for example I need to retrieve data from 6 different queries when I load my app)

Solution

  • Finally I found a way to do it based on this GitHub topic : https://github.com/ParsePlatform/ParseUI-iOS/issues/53

    Here is the function I use :

    func findObjectsLocallyThenRemotely(query: PFQuery!, block:[AnyObject]! -> Void) {
    
        let localQuery = (query.copy() as! PFQuery).fromLocalDatastore()
        localQuery.findObjectsInBackgroundWithBlock({ (locals, error) -> Void in
            if (error == nil) {
                println("Success : Local Query", msg: "\(query.parseClassName)")
                block(locals)
            } else {
                println("Error : Local Query", msg: "\(query.parseClassName)", error: error)
            }
            query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
                if(error == nil) {
                    println("Success : Network Query", msg: "\(query.parseClassName)")
                    PFObject.unpinAllInBackground(locals, block: { (success, error) -> Void in
                        if (error == nil) {
                            println("Success : Unpin Local Query", msg: "\(query.parseClassName)")
                            block(objects)
                            PFObject.pinAllInBackground(objects, block: { (success, error) -> Void in
                                if (error == nil) {
                                    println("Success : Pin Query Result", msg: "\(query.parseClassName)")
                                } else {
                                    println("Error : Pin Query Result", msg: "\(query.parseClassName)", error: error)
                                }
                            })
                        } else {
                            println("Error : Unpin Local Query", msg: "\(query.parseClassName)", error: error)
                        }
                    })
                } else {
                    println("Error : Network Query", msg: "\(query.parseClassName)", error: error)
                }
            })
        })
    }
    

    TO DO : I need to add the "lastUpdateDate" option to fetch only modified data from network.