C4: V1 v V2

C4
C4
Dec 9, 2015 · 7 min read

This year we’ve completely rebuilt C4. It’s more solid, more flexible and definitely more badass than before. In doing so, we’ve changed a LOT.

Here is a brief overview of those changes.

Swift

C4 is now 100% Swift (2.0). No more square brackets. Throughout the api we’ve taken advantage of all the new facets of Swift, including things like tuples, optionals, initializer inheritance, initial stored values, generics, subscripts, closures, new control-flow statements (e.g. for-in), advanced operators… I could go on.

Keeping with our fundamental guidelines for C4, our new API is very Swift-like (similar to how the old version was very ObjC-like). So, if you’re learning C4 you’re actually learning Swift. Or, if you’re experienced with Swift, then picking up C4 will be very easy.

Blocks

Everywhere! We’re now using blocks in almost every part of the api.

Animation Blocks

Creating an animation used to look like this:

You would set the duration, then any changes that happened to properties after that would create individual animations and then run.

Now, animations are their own objects that accept blocks of code to execute:

Check out the new way of creating animations with blocks in the next section.

Delay blocks

Creating a delay used to look like this:

Now, we do things like this:

Blocks Everywhere

These are just 2 examples of how C4 uses blocks, and there are a lot more examples I could show. However, I just want to point out that significant change in our approach to a block-based api. Throughout the rest of this article you’ll start to see how blocks appear everywhere.

Animations

C4 used to rely heavily on implicit animations, but now we’ve shifted to executing blocks of animations. Creating an animation used to look like this:

You would set the duration, then any changes that happened to properties after that would create individual animations and then run. This approach was pretty decent for V1, but getting into complex animation sequences was very tricky… For example, wanting to have 2 separate animations happen with distinct timing on the same object was a bit of a hassle:

In cases like this, the durations would collide with one another because they were being set in the same method.

Animation Objects

Now, animations are their own objects and can handle changing a variety of properties of different objects, etc., rather than being restricted to the property changes of individual views.

Property changes for both the circle and the square will inherit the autoreverse/repeat characteristics of the animation. We can also store that animation as a variable and use it throughout our app (e.g. whenever an event occurs).

Animation Completion

Animations also have completion blocks. So, if you want to do something with an object after it has finished animating you can do something like this:

This will animate the background of the canvas for 5 seconds, then when that’s complete it will switch immediately to another color.

Animation Groups

Previously, animating a group of objects was pretty heavy-handed. You’d create all your animation code for every case, stick that into a method, then call all the methods sequentially from another method… It might have looked something like this:

Now, it looks something like this:

And, when you animate the group, everything initiates at the same time.

Animation Sequences

C4 also has sequences.

Instead of something like:

We now do:

And, each animation in the array executes after the previous one has completed.

Gestures

We’ve also overhauled the interaction mechanism. Where we once took advantage of a combination of touch methods as well as gestures, we now stick solely to adding gestures to objects. It’s a nice, cleaner way of handling interaction.

In the past, every object was implicitly observing touches through methods like:

Internally, these methods looked like:

We found that the overhead of 2 separate conceptual interaction models (i.e. touches and gestures) was inappropriate. Also, this approach required subclassing an object in order to customize a reaction to tapping or moving, etc. Furthermore, adding block-based gestures makes it so easy to handle interaction.

Now, we do the following:

Where the color of the canvas changes when a square is tapped.

And…

Where the position of a square is centered to the user’s finger as they drag around the canvas.

Observers

Say you want to know when something has happened, for example you want to know when a movie has finished playing, or when a method has run, but you don’t want to have a hard reference to an object (or set of objects) in that method. You use an observer.

In the old version of C4 you could tell any object to listen for a message, and specify a method to run when that message comes through. The syntax used to look like this:

And, to send a message an object could do the following:

However, this technique suffered from the same kind of thing as the touches approach above: you often had to subclass to properly change an object’s behaviour. Again… Blocks to the rescue!

Instead, we now do the following:

And, posting is just as easy:

Abstraction: Core & UI

The entire api has been significantly abstracted. For example, we used to have a class called C4Control that was the base class for all visual objects in C4. That class had just over 1000 lines of code… It was huge.

Now, that class is replaced with a basic C4View (~600 lines, incl. comments) and any non-critical or conceptually separate components of that class have been abstracted into extensions. For example, the following extensions are separate files:

This makes the api easier to read, makes the structure more clear, and is just generally less heavy-handed than before.

On top of this approach, we’ve separated code into two categories.

Core

There are a core set of classes that represent the objects and structures necessary to work with C4. Included in this are any elements that are not related to a user’s direct experience, but are necessary for the function of the framework.

UI

All visual / media objects are part of the UI section of the project. These include controllers, filters and extensions that have to do specifically with visible or audio media.

UIKit Extensions

Finally, we’ve included a bunch of extensions that make working between C4 and UIKit easier. Though not exhaustive, these extensions make a significant difference when needing to add views, convert points, and so on…

UIViewController

UIViewContoller now has a canvas object. This is a C4 version of the object’s view property. Where the following:

… will return a C4View that encapsulates the native view of the controller.

This makes things easier when changing the background color of a native viewController’s view. Instead of:

You can do:

UIView

A C4View is actually a wrapper around a UIView. So, you can’t directly add a view to another view… To handle this (and make things consistent) we’ve included add and remove methods that make things work between UIView and C4View.

This add method also implicitly handles optionals.

There are also:

UIColor / CIColor

Creating a UIColor or a CIColor is possible:

CGStructs

Casting bewteen basic structure types is possible too:

… and of course, the other way around:

FIN

We’ve run through a basic set of changes between the first and second versions of C4. There are a TON more changes that we’re proud about, but too many to dive into.

The new version is badass.

Download it.

Use it.

Let me know what you think.

Thanks to Alejandro and Oliver Andrews.

C4

Written by

C4

Code, Creatively. An open-source API for iOS.