2. View Injection Design

So what problems do we need to solve if we want to create a resilient UI architecture that is able to keep up with changing demands?

Tight coupling with superview Boilerplate layout code To much view subclassing that leads to near duplicate view classes to avoid unwanted properties

A common practice in creating an application’s data layer is to use dependency injection. You might have seen this before when using MVVM and generics in the form of a ViewModelController . This will ensure that every subclass of ViewModelController will have a view model that can be injected during the initialization.

By tweaking what “injection” means for the context of views, generics could be used to specify which kind of view to initialize in abstract wrapper and layout view classes. Let’s take a look at what this looks like.

Abstract Wrapper Views

Need to use a UITableView or UICollectionView in your app? No problem, just make a subclass of either UITableViewCell or UICollectionViewCell and your done. Except wait… you created tight coupling with the cells superview. Your new cell can only be used with a table or collection view, not both. How can we fix this? Create a abstract class for each cell type that uses generics to inject a regular UIView into the cell. We can even make a protocol that will forward the key function prepareForReuse to our injected view.

Note: preferredLayoutAttributesFitting is for self sizing cells with auto-layout

Now, we can go ahead and subclass UIView and inject it into the cell. It now becomes easier to use UITableView and UICollectionView interchangeably with the same views. Maybe you have a screen with a static layout? Well now you can reuse the views used in the cells by just using a UIScrollView and arranging the views directly.

Other examples:

Layout View Classes

Like before, we will use generics to define a particular layout for a series of one or more views. More often than not you will end up needing views that have subviews spaced out identically. These subviews may need to be different types but that’s why we can use generics again so the desired type can be injected. For example, we are making a form for a user to edit their profile.

Looking at the rows of this form we see that our layout class should support 3 injectable views. A left view, right view and an accessory view.

The left and accessory view will need to be tightly space so that they only expand to the required width of the views intrinsic size.

Meanwhile, the right view will need to expand filling the extra available space.

Lastly, we can define a minimum height so that this view will auto-size when injected into a TableViewCell or CollectionViewCell .

We use content hugging/compression to set which views can expand/shink

Other examples

Definition View Classes

After developing our layout class we can subclass it and inject the correct components. These cells become the final step in the “View Injection Design” as they are the definition class which add more recognizable variable names to access the generic view variable names. These classes can also be styled to the theme of your app or you may choose to do that in the components you inject directly.