When designing an iOS app for one of our APIs, we like to make a Swift class for the response data to make it easier to work with. These classes follow the same pattern every time: An initializer function that parses the returned dictionary into the class variables, an isEqualTo function to compare two objects, and a toJSON function that takes the object and puts it back into a dictionary so it can be sent back to the API. While I was working on writing up a class for our new project I was wishing there was some way I could take our JSON model and turn it into a Swift class. After all, we already had an example JSON object written up and the class was suppose to match that.
Luckily enough, Lab Day was the next work day. I had always wanted to write code that writes code since it just sounds kind of silly. I took this opportunity to solve my problem of repetitive code.
My first step was to only focus on a JSON object that contained simple types like strings or ints. That way I didn’t have to worry about the extra complexity of arrays or objects. My first task of the day was to figure out how to get the variables I needed from the JSON object to an array of Javascript objects. While simple enough for the primitive variable types, I did have to take into account casing. We use snake_case for key names when sending data via API and camelCase for variable names inside our code. So one short parsing function and case converter later I was able to get an array of variables.
So then came the fun part: actually writing code to write code. I created an array to store all of the strings I would later output. I looked back at some of my old code that I would try to emulate to see how I should proceed. It turns out the code follows a very simple pattern of a few lines of either starting or ending a block of code, followed by a chunk of lines, one for each variable. So the code I wrote followed a similar structure: Adding a few lines to the array to end one function and begin another and then going through a for loop to do something with each of the variables.
By lunchtime I was able get a working prototype that could take a simple JSON object and turn it into a single Swift class. That was great, but it wasn’t very feasible to actually use. The objects we would normally be receiving contain arrays, and objects, and arrays of objects. Handling these types of objects would be an extra challenge.
First of all, I needed to add a couple extra fields to the Javascript objects I was using in order to handle the extra complexity. I need to know if I was dealing with an array, or just an object. If I was dealing with an array, I needed to know what type that would be an array of. Another thing I had to do was add more loops into my code. Not my Javascript code since I was already looping through each variable. I needed to add loops to the Swift code so each item in an array could be initialized, compared, or made into JSON.
Lastly, if I was dealing with some type of object, I needed to recursively call this function so the new object’s Swift class could be created.
I didn’t get the output I wanted on my first try, which led to some really interesting debugging. If you have an extra && at the end of a long condition in an if statement, it is an easy fix. All you do is delete it. But when the error actually lies in another code, things get a little trickier. Trying to think through where my error was and what I needed to change was a fun challenge.
It was really interesting working on this project. Being one step removed from the code you wanted to end up with made me think about coding in a different way. If you want to check out the code or use it for yourself, you can find it here on Github.