Firebase: Totally Not Parse All Over Again (Unless It Is) (CocoaConf San Jose, Nov. 2016)


Published on

With Facebook shutting down Parse, everybody knows to never again depend on a third party for their backend solution, right? Sure, and after you spend six months trying to write your own syncing service, how's that working? In 2016, Google has added a ton of features to Firebase, their popular backend-as-a-service solution. Firebase's primary offering is a realtime database in the cloud that syncs changes to and from multiple concurrent users, and their Swift-friendly iOS SDK makes it ideal for mobile use. In this session, you'll learn how to set up a Firebase backend and build an iOS app around it.

Published in: Software
1 Comment
  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Firebase: Totally Not Parse All Over Again (Unless It Is) (CocoaConf San Jose, Nov. 2016)

  1. 1. Firebase: Totally Not Parse All Over Again (Unless It Is) Chris Adamson (@invalidname) CocoaConf San Jose • November, 2016 Slides available at Code available at
  2. 2. Firebase • Founded in 2011 • Offshoot of Envolve, a chat service that game developers started using to sync state across devices • Main product is a realtime database • Acquired by Google in October 2014
  3. 3. platform-for-mobile-developers/
  4. 4. Firebase @ Google • 470,000 developers using Firebase • Arguably the star of Google I/O 2016 • Analytics (from developers of Google Analytics) • Notifications (based on Google Cloud Messaging)
  5. 5. Realtime database • Cloud-based NoSQL database • Syncs instantly across devices, handles going offline • Client SDKs for iOS and Android, REST for web • Free tier supports 100 simultaneous users, 1GB storage
  6. 6. Getting Started • Create app on using your apps bundle identifier • Download and add GoogleService-info.plist to your project
  7. 7. Getting Started • Add the Firebase Cocoapod • As with all things pod, remember to use .xcworkspace instead of .xcproj from now on • Yes, it is possible to add the frameworks without Cocoapods
  8. 8. Getting Started • Initialize Firebase in application(_: didFinishLaunchingWithOptions:) import Firebase func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. FIRApp.configure() return true }
  9. 9. Demo
  10. 10. Wait, what the… • Firebase I/O works with a local cache, which in turn syncs with the backend • With good connectivity, syncing to backend and other devices is instantaneous • When offline, you can keep working with your local db, which syncs when you’re back online
  11. 11. Tree-structured data
  12. 12. Tree-structured data • Your database is basically one big JSON tree • You access branches and nodes by path • e.g., /sessions/adamson-firebase/title • You can query at a given location, but this is not a relational database. • If you want to do a table join, you structured your data incorrectly. Prefer flatness.
  13. 13. Getting a Firebase Reference • FIRDatabase.reference() returns root of tree as a FIRDatabaseReference • Child returns the named child as a FIRDatabaseReference firebaseSessions = FIRDatabase.database().reference(). child("sessions")
  14. 14. Now What?
  15. 15. Observing Firebase • All interactions with Firebase are asynchronous • You don’t read the value of a location, you observe it for changes • Contents of the child are passed to you on every change
  16. 16. Observe! • eventType: the type of event you want to observe (value, child CRUD, etc) • block: a closure to execute on these events • returns a handle (dispose it in deinit, or earlier) firebaseHandle = firebaseSessions?.observe( FIRDataEventType.value, with: { [weak self] (snapshot) in self?.parseSessionsFrom(snapshot) self?.tableView.reloadData() })
  17. 17. Parse! • Observer block receives a FIRDataSnapshot for every change • Immutable, fetch contents with .value() • Value types: NSDictionary, NSArray (rare), NSString, NSNumber [or Swift equivalents]
  18. 18. Parse sessions list private func parseSessionsFrom(_ snapshot: FIRDataSnapshot) { guard let fbSessions = snapshot.value as? [String : Any] else { return } sessions.removeAll() for (id, value) in fbSessions { if let sessionDict = value as? [String : Any], let session = Session(id: id, dict: sessionDict) { sessions.append(session) } } }
  19. 19. Parse a session init? (id: String, dict : [String : Any]) { guard let title = dict["title"] as? String, let speakerName = dict["speakerName"] as? String, let description = dict["description"] as? String else { return nil } = id self.title = title self.speakerName = speakerName self.description = description } Note: id is the node name (the key in the dictionary on the last slide)
  20. 20. Tip! • FIRDatabaseReference.url can be pasted into your browser to view the Firebase console for that location in your db.
  21. 21. Demo: Writing data back to Firebase
  22. 22. Creating a location if let oldId = UserDefaults.standard.string(forKey: "userId") { firebaseUser = firebaseAttendees?.child(oldId) } else { firebaseUser = firebaseAttendees?.childByAutoId() let newId = firebaseUser?.key let firebaseUserName = firebaseUser?.child("name") firebaseUserName?.setValue("Foo Bar") UserDefaults.standard.setValue(newId, forKey: "userId") UserDefaults.standard.synchronize() }
  23. 23. childByAutoId()
  24. 24. Setting a value let firebaseUserFavorites = firebaseUser?.child("favorites") let firebaseFavorite = firebaseUserFavorites?.child(sessionId) firebaseFavorite?.setValue(true)
  25. 25. Lists of stuff • Convention is to have a dict where keys are ids and values are just “true”
  26. 26. Arrays in Firebase ಠ_ಠ • A dictionary with numeric keys in order will be sent to your observer as an array rather than a dictionary • Not as convenient as you’d think. Pretty much a Firebase anti-pattern
  27. 27. observeSingleEvent() favoriteTitles.removeAll() for (sessionId, _) in fbFavorites { firebaseSessions?.child(sessionId).child(“title").observeSingleEvent( of: FIRDataEventType.value, with: { [weak self] snapshot in if let title = snapshot.value as? String { self?.favoriteTitles.append( FavoriteItem(favoriteId: sessionId, title: title)) self?.tableView.reloadData() } }) } Note: observeSingleEvent() does not return a handle for you to hold on to and dispose later
  28. 28. Authentication • Firebase provides an email + password system • Can also use Google, Twitter, Facebook, or GitHub credentials • Or roll your own and provide an OAuth token
  29. 29. Database rules • Define per-branch access based on authentication • Can require that user just be logged in, or that their Firebase user id matches the one that created the node
  30. 30. Default access // These rules require authentication {   "rules": {     ".read": "auth != null",     ".write": "auth != null"   } }
  31. 31. Public access // These rules give anyone, even people who are not users of your app, // read and write access to your database {   "rules": {     ".read": true,     ".write": true   } } Private access: just make read/write false
  32. 32. User access // These rules grant access to a node matching the authenticated // user's ID from the Firebase auth token {   "rules": {     "users": {       "$uid": {         ".read": "$uid === auth.uid",         ".write": "$uid === auth.uid"       }     }   } }
  33. 33. Case Study
  34. 34. MathElf • “Über for high-school math tutoring” • Students request help on a topic, are paired with a tutor in less than a minute • Student and tutor work on problems via voice chat and a shared whiteboard
  35. 35. MathElf Demo
  36. 36. MathElf & Firebase • Authentication and user financials are done through (parent company) backend, making REST calls to Firebase • Basically everything in the whiteboard and session history is Firebase
  37. 37. User Metadata
  38. 38. Page Contents
  39. 39. Picture metadata
  40. 40. Drawing paths
  41. 41.
  42. 42. Firebase “con”s • Limited visibility when something goes wrong • When things don’t sync, is it them or you? • Single point of failure, owned and operated by a third party • Could be Parse all over again
  43. 43. Takeaways • Firebase database-as-a-service is well-suited to mobile apps • Real-time sync, still works when offline • Structure your data as flat JSON trees, not SQL- like tables • All reads are asynchronous. Hope you like closures/blocks.
  44. 44. Firebase: Totally Not Parse All Over Again (Unless It Is) Chris Adamson (@invalidname) CocoaConf San Jose • November, 2016 Slides available at Code available at