Hackership, first month retrospective

One month has passed at the Hackership and I can say that I learned a great deal about a lot of subjects : implementing Facebook and Google connect on iOS and connecting server side in php, map clustering, implementing UIpage to swipe through pictures, creating a scrollview with a blur, creating objects and constraints programmatically, using APNS library to send push notification in php, concurrency vs parallelism programming , multithreading, infinite scrolling etc…

But more than anything I really learned about the joy of working with passionate people, through peer learning, hackatons, or just by talking excitedly about projects and technologies around lunch. I have always enjoyed the freedom of working on my own but there is definitely something to say about co-learning/working, and I will from now on look for coworking spaces whenever I have the opportunity to go travelling.

Anyway, for this week I’d like to talk about a few things: a quick tip to wrap a function in a completion block and the best (IMHO) library for clustering.

Wrapping a function in a completion block

Have you ever had an asynchronous function provided by a library which wasn’t implemented with a completion block, so you couldn’t know when it was finished? I have, with Google Sign In library. I was using GIDSignIn.sharedInstance().signIn()  which was signing my user silently, but as it doesn’t return anything I was able to know at which precise moment the function returns. Sure, it calls its delegate method at the end and I could add a notification there, but as I had many other function depending on it and with the way mas code is structured it wasn’t convenient.

So after many trials I came up with two options: creating a custom delegate, or simply by wrapping the GIDSignIn.sharedInstance().signIn()  in an another function which calls an external completion block. It would look like this:

  1. We declare the variable: var glCompletion:(status:Bool) -> ()  to store the function completion block:
    class KYController:NSObject, GIDSignInUIDelegate, GIDSignInDelegate {
        
        // List of constant properties of the class
        private let query: queryAPI
        var glCompletion:(status:Bool) -> ()
        
        //fb & gl connect
        var fbLoginManager : FBSDKLoginManager
        var gSignIn: GIDSignIn
    
        override init() { //2
            glCompletion = {(status:Bool) -> Void in }
            gSignIn = GIDSignIn.sharedInstance()
            
            super.init()
            
            // Initialize Google + sign-in
            var configureError: NSError?
            GGLContext.sharedInstance().configureWithError(&configureError)
            assert(configureError == nil, "Error configuring Google services: \(configureError)")
            GIDSignIn.sharedInstance().delegate = self
            
            gSignIn.uiDelegate = self
            gSignIn.scopes = ["https://www.googleapis.com/auth/plus.login"];
            gSignIn.shouldFetchBasicProfile = true
        }
    
        func glSignIn(completion: (status:Bool) -> ()) //3
        {
            glCompletion = completion
            GIDSignIn.sharedInstance().signIn()
        }
    
    } 
    
  2. We initalize it (in `init()`, `viewDidLoad`…)
  3. We then wrap GIDSignIn.sharedInstance().signIn() in a new function in the class, and we assign the completion of the function to glCompletion, so we can access it reuse later. We trurn a class that it initally delegate based into block/completion based.
  4. Finally we can assign true to glCompletion  once the user is created and send this value back to the controller:
    //Send token to the server https://developers.google.com/identity/sign-in/ios/backend-auth
    func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
        if (error == nil) {
            let query = queryAPI()
            query.googleConnect(token, completion: { (success) -> () in
            if success {
                  println("Log in with google successful.")   
                  self.createLoggedInUser({ (success) -> () in
                  self.isUserLoggedIn = success
                  dispatch_async(dispatch_get_main_queue())  {
                 //here send that the user is logged in to the view controller so it can dismiss the view
                      self.glCompletion(status: success)
                  }
              })
           }
           else {
             println("Log in with google failed.")
          }
          })
       }
    }

     

Part 2: Clustering annotations on a map in swift