Generics and the Art of Inference Part 1 of 3

The power of inference in Swift generics is something I find most people underestimate and underuse. Personally generics and inference has saved me from writing tons of boilerplate and duplicated code. In any case there is a ton I’d like to share about this topic, but to begin here are a couple common cases where I have found it useful…

Dequeueing Cells in a UITableViewCell/UICollectionViewCell

If your cell identifier and classname are identical, this UITableView extension is a great shortcut for retrieving a cell for doing two actions with a single key. It also is a great way of remembering what your cell identifiers actually are.

(1) Here we get the cell identifier by converting the class parameter into a string.

(2) Then we pass the identifier into dequeueReusableCellWithIdentifier and cast back to our type T, which we already know from passing in the class type as T.type. Now we no longer need to cast to a type inside our cellForIndexPath function:

And of course an extension on UICollectionView would look almost identical.

Loading From Nibs

We first need to create a protocol with an init for our nib loading requirement. Since UIVC already has this initializer, we can extend UIVC to VCNibable for free.

Now we reuse the cell dequeueing logic:

We then utilize the VCNibable protocol to genericize the init, as just using UIViewController.init(nibName:bundle:) for a subclass will load our custom VC with the wrong class type.

Using the same logic as in the dequeueing example, T.Type input allows us to first get the identifier by converting the type to a string (we assume the type and nib are the same name) and second use T for a generic return type.

The protocol conformance on T <T: VCNibable> then lets us call the init to retrieve the nib for that class.

we can now get a VC from a nib like so:

Going a step farther we can extend UIViewController to be able to present nibs from classes as easily as we can with segue identifiers:

Here we use NibLoader.loadNibFromClass to retrieve our nib VC with the proper class, and pass it into presentNibVC

presentNibVC then presents our VC and gives us a more sophisticated completion block to prepare the view with.

(1) Only types inheriting from UIVC can be presented by our UIVC, so we use guard and cast to ensure our nib inherits from UIVC. We used a generic here instead of UIVC in the param so that we can later pass it into the completion later.

(2) Since presentViewController has a completion block in the form of (() -> Void)?. I am just calling our custom completion(T -> Void) inside a compatible closure, so that we can finish with access to the view we are presenting, without all the extra mess we might otherwise have.

And finally we can do something concise and magical like so:

We could even go a step further and add a pre-present closure, to specify how to present the view, i.e. modally, over current context, etc.