Wednesday, February 21, 2018

Firebase 'Friendly Pix' : Data structure, and Auth

Googles Firebase team have created a demo social media app called FriendlyPix, to give some examples of best practise when creating a social network with a Firebase back-end. Its like a simple Instagram, allowing users to upload photos, comment, etc.

You can get the original iOS version from here.  At the time of writing, theres a design document, which gives a general overview of data structures and how things work in a superficial way, which is available here.  I haven't found a more detailed discussion of the iOS version though, so thats what I'm aiming to do with some articles here.

Data Structure

Its handy to have a look at how they have structured the data, considering their social network (like most) has users, posts, comments, likes, followers, and a personal 'news' feed.  Ive sometimes wondered on the various merits of alternatives ways of structuring that data.  The solution for FriendlyPix is described in the design doc, but heres an overview:
  • (root)
    • people
      • user_id
        • searchIndex (full_name, reversed_full_name)
        • posts (ids..)
        • etc
    • posts
      • post_id
        • author (full_name, pic, uid)
        • full_storage_uri
        • etc.
    • comments
      • author_id
        • post_id
          • author :
          • text :
          • timestamp : etc.
    • feed
      • user_id
        • post_id : true
    • followers
      • followee user_id
        • follower user_id
    • likes
      • user_id
        • post_id : timestamp

Firebase structures data in the database as JSON. You can examine it at any time on the Firebase console and have a look at what is where, which makes it nice and easy to use. So at the top level the data is sorted into these 6 arrays : People, Posts, Comments, Feed, Followers and Likes. Below that, People and Posts then have a unique key to identify each user or post, and within each lie the details. Comments, Feed, Followers and Likes are structured first with the id of the user that each relate to - so for e.g. the first set of keys in the comments array is an array of author_id, which is a copy of the user_id of the user that created the comment, followed by the post_id that the user commented on, and then the comment details. Similarly the Likes array first has an array of keys of the user that created the like, then the post_id that was liked.

Within a single user_id element, there are full_name and reversed_full_name properties, which is done to help speed up searches for users.

Firebase Auth

Firebase has a whole pod dedicated to 'Auth', and a section on the Firebase console. In general everything within Auth is dedicated to helping us recognise who a user is, and give them access to data, or get them 'logged-in'.

For a simple start in getting users authorised for your app, you can enable email/password authorisation in the Auth area of the Firebase console. Then the following code within an iOS application would create a new user, and if successful, the user will be logged in (via the code in the completion closure).


The default setting on the Firebase database is that without this authorisation, a user cannot access data. So on a simple level, this code has also unlocked the database for the app to query from now on (unless you change settings and open it up for unauthorised users).

Having authorised the user, the app goes on to ensure that the user details have been added into the People array in the database. The following code will add a new user into that People array in the main database, if it doesn't already exist, or update it if its there already.


As I mentioned above, the People array within the database has user_id's as keys at the top level, which is why the database reference above looks like : .reference(withPath: "people/\(user.uid)"). Beyond that you can see the dictionary structure that will populate that user in the database - profile picture URL, full name, etc.

At no point do you need to go into the Firebase console and add properties to data models or anything like that. The code snippet above has directly created the JSON in the database, or it has updated the entry if that key (the user_id) existed already. This is one of the reasons why Firebase is so nice and easy to use - you just send dictionary structures to the database with key values that you have decided upon, and the data is created and saved away for easy extraction later.

I'll be writing a few more articles on this app shortly. I'll be looking at how the Feed page organizes batched downloading of posts next. All feedback or questions welcome of course.

Tuesday, February 20, 2018

UIView broken .. by a print statement?

Is your print statement causing your app to crash?  Well thats what happened to me this morning.  Totally unexpected but undoubtedly true.  Heres what happened.

Ive have a large UIView in the app Im working on right now, with loads of IBOutlets.  There are two instances of charts, various labels, textfields, etc.  All are linked to my UIView via explicitly unwrapped optionals, as Apple advise, like this :

@IBOutlet weak var detailBox: UIView!


Now at the same time as this view is being loaded, I have downloads happening in the background.  Large downloads, of XML, as it happens.  When each download finishes, I have a parser that is taking that XML apart and turning it into useful local objects.  Eg :

convenience required init(xml: AEXMLDocument, patient: Patient?, externalContext: NSManagedObjectContext?) {

        self.init()

        //print("------- get EOBS info by location -------")

        //print("XML : \(xml.xml)")

        self.isValid = true


You can see the start of the parser class there. Those commented print statements are what is breaking my UIView. How you ask? Well Im attempting to print out what are large chunks of XML. My UIView loading work must happen on the main thread, and that main thread is being held up by the printing process, which takes several seconds.

Meanwhile, my UIView is being asked to render the chart. My IBOutlets are explicitly unwrapped optionals, and Swift fans will know that if you try and use an implicitly unwrapped optional when it is nil, the result is in instant crash. And that is what happened in my case. As Curtis Herbert points out on his blog, doing as Apple suggests and always using implicitly unwrapped optionals for UIView IBOutlets is not always a good idea.

My immediate solution? Removing the print statements got rid of the crash, as the main thread had plenty of time to render the view before using my unwrapped properties. But in general this doesnt feel very safe - so the real fix here would be to use optionals, and unwrap as you go. Its more work, but its safer.

Wednesday, February 14, 2018

Loading custom UIViewController from .xib file

Occasionally I like to create UIViewController files within their own .xib files, rather than within a storyboard.  One example of when I favour this approach is for when I have a UIViewController that can appear above multiple different VC's within the app, such as a login screen for example.  In this case its not really part of the 'storyboard' flow of an app, linked by a segue.  A big advantage too is that I can create and develop my xib and be sure of no conflicts with other developers on a team, which is not the case with storyboards.  You can of course help to simplify storyboards and avoid conflicts by having multiple storyboards dedicated to different areas of an app.  But in the case of a login screen, theres no flow there necessarily - just a single screen I need to show anywhere.  So a single .xib UIViewController is a nice easy way to go.  Heres how its set up.

First, make a new UserInterface file, of type View.


Then make a new .swift file to contain the UIViewController class you are making, and add the basic methods :


Now return to interface builder to edit the new .xib file you made.  First, go to Files Owner and set the class as your new view controller class (in my case, TestViewController).  Tip - if you start typing the class and it autocompletes, you know you have it ready to go.  Its possible to enter the class name here even if the class doesnt exist, and stuff wont work later.

Now, very important bit : set the view property on Files Owner to be the view in your xib.  You do this by Ctrl-dragging from Files Owner onto the view then selecting view from the little menu that appears :


From here, you have properly set up the class, and the xib.  Now you are able to do things like drag properties from your view into the UIViewController class swift file.

To instantiate this in code :


Important to note there : your new UIViewController subclass name (in my case TestViewController) is used both in the name of the call, and as a string in the nib name field.  In that code I present simply by presenting on top of the current view controller.  You can of course do many different things there, for example, pushing on to the current UINavigationController.

One final note - if you try and call to instantiate a UIViewController like this from within the viewDidLoad method of another view controller, it wont work. It is unable to present the view at this stage. You need to go beyond the viewDidLoad phase into viewWillAppear for eg, at which point and beyond, you can do it. All comments welcome of course.

Social Network with Firebase 3 - Infinitely scrolling UITableView of Firebase Items

Ive already talked about the basics of a Firebase social network project , and adding posts in two other articles. Here I want to explain ...