Using C# and .NET thinking, ZombieInjection is a simple iOS app that shows a list of zombies in which you can select one and change its name on a detail screen. The name change then persists back to the list view. For this exercise, I tried to pick a small enough scope while still having enough meat to provide a useful exercise. And let’s be honest, zombies love meat!
I have spent the last couple weeks trying to reconcile my far deeper knowledge of C# with what I’ve been learning of Swift. It has not been very easy. Swift is just similar enough to C# that I get confused when I can’t implement certain features I was used to having in the .NET world.
The final result of this exercise is not perfect, but I am actually pretty happy with it. I will get into some of the more technical details and challenges in some future posts, but for right now I wanted to discuss this example at a high level. You can find the entire project here.
The “Right” Way
Before we get too far into the specifics, there is something you need to know about me, personally, that will help you understand some of the design decisions made: I am always looking for the “right” way to do software development (sometimes to a fault). I’m fully aware that there is no “right” way to create software, but I think we can all agree someways are better than others. The main thing all programming languages share is purists yelling at each other; that is not what I’m trying to accomplish here.
It is not atypical for me to spend a lot of time researching new languages and new technologies to figure out how the experts do it. What I’m applying here is the result of all of those learnings I had in the C#/Xamarin world and combining them with what I’m learning in Swift/iOS. In my prior experience, I found many, many resources on how to write sustainable and testable software. Right or wrong, that kind of onus does not appear to get put on iOS app development. Yes, yes, I completely understand the fact that my iOS app will probably not be around in twenty years, but I would still like to write it as robustly as possible. To that end, you will probably see many places in this example project where I could have taken a much easier route — Please keep in mind that my goal was to figure out a scalable design that I could apply to big and small projects alike.
Prepare yourself — you are going to be hit by a lot of acronyms. In the construction of this app I used MVVM, DI, and IoC (and probably more!) Let’s define these ideas:
MVVM stands for Model-View-ViewModel. This design pattern comes out of the Microsoft .NET world. You can find more on this pattern here. Here is an illustration of the preferred interaction between the components of the pattern:
While listening to many iOS podcasts, it sounds like this pattern is starting to get some traction in the iOS world. I think it is being used a little differently than expected on the iOS side, but that’s fine as I think the main idea of abstracting out your business logic is still the same.
In the .NET world, data binding is a big part of what the ViewModel does. As many of you are aware, iOS does not really do any kind of data binding out of the box. I love data binding to get rid of a lot of boilerplate code so I’ve implemented my example project using the excellent SwiftBond library. With that in place, I was able to write more condensed code and do away with all of the UI element setup code.
Generally, my goal for each ViewController is to boil it down as much as possible. For instance, here is what my detail view controller looks like:
The rest of the actual business logic is buried in the ViewModel (which gets injected when the ViewController is created). This approach leads to much lighter view controllers and the ability to properly unit test your business logic independent of UI code.
DI and IoC
DI stands for Dependency Injection. IoC stands for Inversion of Control. These concepts were initially very hard for me to wrap my head around but now I love them.
They make mocking in unit testing so much easier. I used the Dip framework by AliSoftware to implement these concepts. The main idea here is to use dependency injection, an IoC container, and protocol-oriented programming in conjunction with generics to get you to the point where there is only one place in your code that you are defining all of your concrete dependencies — called the Composition Root. If done right, you end up with one place where you need to define the concrete types; this allows for much easier mocking and stubbing in your unit tests. To learn more, take a look at the excellent book Dependency Injection in .NET by Mark Seemann.
I wrote a more in-depth post about this here.
Services and Repositories
The other architecture patterns I loved from the .NET world were the use of Services and Repositories to abstract where your data is being stored and how you interact with your different data objects. For example, in my project I have a ZombieService which conforms to ZombieServiceProtocol and within that ZombieService there is a Repository of Zombies. For the purpose of this example project, I just create 100 zombies at the start time of the app but you could easily connect this to a web service that is actually persisting your zombie list up in the cloud. The main benefit of doing all this work is that I can then create a ZombieServiceMock and a ZombieRepositoryMock to easily implement all of my unit testing without having a real database be part of the unit tests. To accomplish that, I created a DataServiceProtocol that defines all of the CRUD operations you can do to your zombies which then allows me to easily swap out my underlying database whenever I like.
Soap Box: You may have heard talks given where the point is made that no one ever swaps out their database so database abstraction is a waste of time. Do you know where EVERYONE should be swapping out their database? When you are unit testing!!!
Lastly, the other service I created was an ImageDownloadService which basically wraps around using AlamoFireImage. That allows for easier unit testing and the flexibility to swap out AlamofireImage for something else in the future if needed.
My main goal was to be able to put together a simple project that would allow me to exercise and incorporate many of the robust programming paradigms that I used in the .NET world. For many of you this may seem like overhead, but in my current role we need to create our iOS apps as robustly as possible and I think I managed to find a fairly good solution for the time being. If you you’ve made it down this far and you have some thoughts or questions, I would love to hear them!
P.S. Special thanks to Tyler Longren who runs the placezombie.com website which serves up the zombie placeholder images.