Wednesday, November 21, 2012

CoconutKit 2.0: Containers and animations finally done right

Two and a half years ago, my previous employer bought me a Mac Mini and gave me a simple mission: Investigate iOS development. So I found myself spending a couple of weeks reading documentation, from Objective-C basics to iOS fundamentals, to more advanced topics, making little code experiments which ultimately should give birth to an application. It was love at first sight. Nobody around me was working on iOS at that time, so I was lost alone in a foreign world. It was thrilling.

When I look back at my first application, though, I can nothing but laugh: Clumsy implementations, incorrect patterns, bad design choices. But still I could gain a solid understanding of iOS development core concepts, and some best practices which I still apply nowadays.

Two months later, I started working at hortis, after my old employer decided iOS development was not promising enough to deserve having a dedicated engineer. I tried not to make the same mistakes as before and, guided by a team of already experienced iOS developers, I wrote my first real iPhone application. As I progressed, I decided to stuff everything I found interesting into a static library for later reuse: CoconutKit was born.

It is after I wrote some more applications, mostly for the iPad, that I realised I was spending too much time on repetitive and cumbersome tasks, most notably:

  • The navigation and tab bar controllers look ugly on the iPad IMHO (especially full screen), but how can you conveniently manage your view controller hierarchy easily without them? The short answer is that you cannot, and I became frustrated not being able to do fancier user interfaces more easily
  • I spent too much time writing and tweaking spaghetti code to create beautiful animations, and ensuring that my application state was correctly restored during low-memory conditions
  • Localizing nib files was boring, and my code was becoming cluttered with outlets only needed for this specific purpose (ARC and synthesize by default did not exist at that time)
  • Many applications I wrote use Core Data. Instantiating and managing a model is painful (even with great tools like mogenerator), and writing forms was a pain in the ass (you have to write validation methods, call them manually from the view controller, and keep text fields and underlying model fields in sync)
  • I began tackling those problems one by one and, as I made progress, CoconutKit grew larger. As I finally open sourced version 1.0 in August 2011, most of the above problems had found a quite satisfying solution:

  • To manage view controller hierarchies in an easy way, two container classes were written, HLSPlaceholderViewController (for view controller composition) and HLSStackController (which manages a stack of child view controllers). I carefully implemented those containers so that they can be nested and play nicely with UIKit containers, and so that a predefined set of animations can be applied when transitioning between view controllers
  • HLSAnimation provides a way to define animations in a declarative way. Such animations can then be stored or played backwards, even instantaneously, which eliminates the spaghetti code you usually need to write
  • For fast and painless localization, a mechanism was introduced, with which you can localize labels directly in xib files, without the need to bind any outlet
  • A class was created to implement the usual Core Data boilerplate code you have to write (store and managed context creation, read and write operations). Moreover, a layer was added to Core Data validation so that text fields can be directly bound to the underlying model object fields. This eliminates the need to write validation and synchronization boilerplate code completely
  • As I wrote more applications, though, major limitations and issues arose:

  • CoconutKit 1.x containers were not perfectly compatible with the new containment API introduced with iOS 5, and with the autorotation behaviour introduced with iOS 6. Moreover, transition animations could not be customised, and UIKit containers could not be implemented in terms of CoconutKit ones (for example, there was no way to go back to the root view controller of a stack controller without popping all view controllers above one by one)
  • HLSAnimation was based on UIView animation blocks. For an application I worked on, layer animations were needed, leading to the usual spaghetti code I was striving to avoid
  • Six months ago, I decicded to fix iOS 5 and 6 behaviour, but as I was making progress, I found some refactoring was necessary. As I was making progress, it became clear that a small refactoring would not suffice, and I decided to implement containers again from scratch, eliminating all issues which could not be fixed with the previous implementation. I also decided to refactor animations at the same time, so that new container transition animations could be created.

    The results went far beyond expectations, and I could implement the objects I was dreaming for two years ago:

  • Rock-solid containers, supporting custom transition animations, storyboards, and exhibiting far richer interfaces than UIKit containers. HLSPlaceholderViewController now lets you combine an arbitrary number of view controllers. All containers are compatible with iOS 4, 5 and 6
  • A containment API with which you will be able to write any kind of container, without ever needing to worry about the details of container implementations. That's two years of experience contained in a single class
  • Animations which can combine an arbitrary number of sub-animations, either UIView block-based or Core Animation layer-based, still created in a declarative way, and that implement non-trivial behaviour (pause and resume, starting at arbitrary times, correct behaviour when the application is sent to the background, etc.)
  • I initially planned to release a 1.1.4 or 1.2, but those massive changes justified a major version bump. I am therefore proud to announce that CoconutKit 2.0 is now available from its official github page. This version is a huge leap forward. Start using it now, and create iOS applications like never before!

    In the upcoming weeks, I will write a few tutorials covering the basics of CoconutKit. Those will be added to the project wiki. Stay tuned!

    5 comments:

    1. 4 years ago you were in the situation I am in now: "Go, learn to program this iPhone. If you have questions, there is Google." You probably were not learning the Art of Programming at the same time, as well? So, I thought maybe I can learn some from your experience. I would have liked to include CoconutKit into my project, temporarily. I am quite sure I would have had to replace it with my own code later because of copyright issues of our company and our customers, but I might have won wisdom in the meantime... Problem: XCode keeps asking me to accept the dev.hortis.ch server identity certificate. I keep refusing :) I can not imagine myself asking my boss to link our project to another companies server (with the exception of Apple, naturally) in any way. Is this "behavior by design" or did I make some error you have encountered before, maybe?

      ReplyDelete
      Replies
      1. Oh, I forgot to say I followed the instructions for adding binaries to my project.

        Delete
      2. Sorry, I made a mistake when zipping files (I forgot to remove .svn files). Deleting them should solve your issue.

        You should consider using binaries for CoconutKit 2.0.2, though. Those are sadly not available from github anymore (since the downloads section is now deprecated). To build them, checkout the projet (with its submodules) and build it using the dedicated Xcode target.

        Best regards

        Delete
    2. This comment has been removed by the author.

      ReplyDelete