Today was the first day that Test Driven Development actually justified its existence

I’ve been making apps since iOS 2.2.  People tell me I’m good at it.  Meh.  There’s always a bigger fish.  I love what I do, so chances are I’m not horrible at what I do.

Today was the first day where I used Test Driven Development to actually develop code.  Don’t get me wrong; it’s not like I don’t write unit tests.  I do.  But what I’m referring to right now is where you actually are given the start and passing conditions of a test before there is any code written at all.  In my field of work, this never happens.  The design is ALWAYS a moving target.  Nothing in the startup world is ever known in advance, so although you could write unit tests, it doesn’t always make sense.

I’ve recently been working on the implementation of the rules of Canadian Ice Hockey.  (Don’t ask.)  The sport itself seems pretty straightforward.  Put the puck in the net.  Goal.  Increase Score.  No way!  There are a lot of complicated rules surrounding penalties, but thankfully there is a referee’s handbook that goes over all the complicated scenarios and tells you what the result should be.

Perfect for TDD.  I literally wrote all the unit tests before I wrote the code that would produce the expected results.  I love it because I have to be honest; the solver code I wrote just “feels bad”.  I’m not even certain how parts of it work, and I only wrote it this past week.

What unit tests tell me is: It doesn’t matter!  As long as the tests pass, the code does what it’s supposed to do.  Very satisfying.

 

Stretchy Header UITableView (and how I hate hacks)

I really dislike using a UIViewController subclass to make fundamental functionality of a UIView work.  That said, I will do what needs doing to get the job done.  Sometimes there are no other obvious ways to do something non-typical.

Recently I looked for code that could help me recreate “stretchy header” functionality.  And I found some here.  It wasn’t a bad approach.  It worked.  But somehow seemed a bit brittle, or for a very specific use-case.  It was adjusting contentInset depending on contentOffset value.  That seemed sub-optimal.

I’m currently working on a UITableViewController subclass that should be configurable to have stretchy headers, expandable section headers (see previous post), and scrollable navigation bars (also a post of mine from 2012… will finally (soon) get a fresh coat of paint).

Anyway, I found the easiest way to make stretchy header views.  Simply, you have to subclass UITableView and make sure your UITableViewController subclass uses an instance of it and not of a standard UITableView.  The advantage here is that you don’t need to change any view controller code, so you don’t have issues associated with class inheritance.

Enough talk.  Here’s the code.  You can try it for yourself.

//  HSStretchyHeaderTableView.h
//  TableViewSandbox
//
//  Created by Stephen O'Connor on 23/03/16.
//  MIT License.
//

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface HSStretchyHeaderTableView : UITableView

@property (nonatomic, assign, getter=hasStretchyHeader) IBInspectable BOOL stretchyHeader;

@end

And now the .m file:

#import "HSStretchyHeaderTableView.h"

@interface HSStretchyHeaderTableView()
{
    CGFloat _headerViewHeight;
}
@end

@implementation HSStretchyHeaderTableView

- (void)awakeFromNib
{
    // NOTE, You will have to modify this solution if you don't use InterfaceBuilder!
    _headerViewHeight = self.tableHeaderView.bounds.size.height;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    if (self.hasStretchyHeader)
    {
        CGRect headerFrame = self.tableHeaderView.frame;
        
        if (self.contentOffset.y  _headerViewHeight)
        {
            headerFrame.origin.y = 0;
            headerFrame.size.height = _headerViewHeight;
            self.tableHeaderView.frame = headerFrame;
        }
    }
}

@end

Pretty easy! Happy coding!

IB_DESIGNABLE UIView using a custom CALayer (for animations)

I’m a very visual person.  If I can use Interface Builder, I do.  I like it mainly for the separation of concerns, and really who doesn’t like a WYSIWYG way of inspecting your UI ??

So, I had a somewhat unique scenario in that I want to have a UIView that has a custom CALayer that has properties I can animate.  (See here for some background on that, though I will touch on it below:  https://www.objc.io/issues/12-animations/animating-custom-layer-properties/ )

But I also want to be able to configure these properties in Interface Builder via the Inspector pane.

I found a way to do this, although it’s tedious.  In short, you have to define a custom layer, deal with it’s display and animation, and wrap the layer properties on your UIView subclass.

What?  Fine.  Here’s the simplified code to show you how it would work for something like a custom progress bar:

//  HSProgressView.h
//  Created by Stephen O'Connor on 17/02/16.
//  MIT License.

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface HSProgressView : UIView

@property (nonatomic, assign) IBInspectable CGFloat progressValue;  // clamps between 0...1
@property (nonatomic, strong) IBInspectable UIColor *barColor;

- (void)setProgressValue:(CGFloat)progress animated:(BOOL)animated;

@end

And the .m file

//  HSProgressView.m
//  Created by Stephen O'Connor on 17/02/16.
//  MIT License.


#import "HSProgressView.h"

@interface HSProgressView()

+ (NSArray*)customLayerProperties;

@end

// HERE WE DEFINE A LAYER THAT IDEALLY WE'D PREFER TO DO IN
// A UIView SUBCLASS IN drawRect:, BUT TO LEVERAGE THE ANIMATION
// PROPERTIES OF COREANIMATION, WE DEFINE THEM IN A CALayer THEN
// WRAP THEM
@interface _HSProgressViewLayer : CALayer

@property (nonatomic, assign) CGFloat progressValue;
@property (nonatomic, strong) UIColor *barColor;

@end


@implementation _HSProgressViewLayer

// these methods are generated at runtime
@synthesize progressValue, barColor;

+ (BOOL)needsDisplayForKey:(NSString *)key
{
    // HERE WE SAY IF ANY OF THESE PROPERTIES CHANGE,
    // SHOULD IT REDRAW THE LAYER
    
    // I JUST SAY YES FOR ALL OF MY CUSTOM PROPERTIES
    // BUT YOU CAN CONTROL THIS HERE
    for (NSString *propertyName in [HSProgressView customLayerProperties]) {
        if ([key isEqualToString:propertyName]) {
            return YES;
        }
    }
    
    return [super needsDisplayForKey:key];
}


// THIS IS WHERE YOU DEFINE WHICH PROPERTIES CAN BE ANIMATED
// AND HOW.  Duration, timing, etc.
// In our case, we only want to animate progress, but not color
- (id)actionForKey:(NSString *)key
{
    // if (key corresponds to a property name I want to animate...)
    if ([key isEqualToString:@"progressValue"])
    {
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key];
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        
        if ([key isEqualToString:@"progressValue"])
        {
            // LOOK HERE!  It's outlined in that post listed above, but
            // if you animate, you need to look to the presentationLayer
            // as it holds the currentValue *right now* or *on screen*
            // if you didn't call presentationLayer, the progress
            // value is going to be the value you are trying to animate to
            // and you would see nothing!
            
            
            animation.fromValue = @([self.presentationLayer progressValue]);
        }
        
        // other animatable properties  here...
        
        return animation;
    }
    return [super actionForKey:key];
}

- (void)display
{
    // again, takes the value that it currently is animating to,
    // if you called self.progress it would always return the final value.
    
    // that being said, if we want to inspect it in interface builder
    // we have to omit animation and just look at the value it 'wants' to be
    CGFloat progress;
#if !TARGET_INTERFACE_BUILDER
    progress = [self.presentationLayer progressValue];
#else
    progress = [self progressValue];
#endif
    
    
    //create drawing context
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
    
    // backgroundColor is a property on CALayer, but we still need to draw him!
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(ctx, self.backgroundColor);
    CGContextFillRect(ctx, self.bounds);

    
    // now for our custom properties
    UIBezierPath *path;
    
    CGRect drawRect = self.bounds;
    drawRect.size.width = MAX(0, MIN(1, progress)) * drawRect.size.width;
    
    path = [UIBezierPath bezierPathWithRect:drawRect];
    [self.barColor setFill];
    [path fill];
    
    //set backing image
    self.contents = (id)UIGraphicsGetImageFromCurrentImageContext().CGImage;
    UIGraphicsEndImageContext();
}

@end


static NSArray *HSProgressViewLayerProperties = nil;

@implementation HSProgressView

+ (Class)layerClass
{
    return [_HSProgressViewLayer class];
}
    
+ (NSArray*)customLayerProperties
{
    if (!HSProgressViewLayerProperties) {
        
        HSProgressViewLayerProperties = @[
                                          @"barColor",
                                          @"progressValue"
                                          ];
    }
    return HSProgressViewLayerProperties;
}

#pragma mark - Generic Accessors

// we wrap the properties on the layer, so we override this
// for integration into Interface Builder's IBInspectable properties

- (void)setValue:(id)value forKey:(NSString *)key
{
    for (NSString *propertyName in [HSProgressView customLayerProperties]) {
        if ([key isEqualToString:propertyName]) {
            
            [self.layer setValue:value forKey:key];
            
            return;
        }
    }
    [super setValue:value forKey:key];
}

- (id)valueForKey:(NSString *)key
{
    for (NSString *propertyName in [HSProgressView customLayerProperties]) {
        if ([key isEqualToString:propertyName]) {
            return [self.layer valueForKey:key];
        }
    }
    return [super valueForKey:key];
}

#pragma mark - Public Methods

- (void)setProgressValue:(CGFloat)progress animated:(BOOL)animated
{
    // if animated is yes, it gets it's information about how to
    // animate it via actionForKey: on the custom layer implementation!
    
    if (!animated) {
        [CATransaction begin];
        [CATransaction setDisableActions:YES];
    }
    
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    layer.progressValue = progress;
    
    if (!animated) {
        [CATransaction commit];
    }
}

#pragma mark - Layer-backed Accessors

// SADLY WE HAVE TO WRITE A LOT OF BORING CODE HERE TO WRAP THE ACCESSORS.
// IF SOMEONE KNOWS BETTER, PLEASE TELL!
- (void)setProgressValue:(CGFloat)progressValue
{
    [self setProgressValue:progressValue animated:NO];
}

- (void)setBarColor:(UIColor *)barColor
{
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    layer.barColor = barColor;
}

- (UIColor*)barColor
{
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    return layer.barColor;
}

- (CGFloat)progressValue
{
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    return layer.progressValue;
}


#pragma mark - Layout and Drawing

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.layer.bounds = self.bounds;
    [self.layer setNeedsDisplay];  // because the layer follows the size of the view, whose contents fill the view's frame.
}

@end

There it is! Copy-paste this into your own class and try it out in Interface Builder. Now you should see how you can extend this for your own purposes.

The Perils of Hackers in your Team

I’ve currently joined a project as the only iOS Developer.  I’ve inherited a codebase that’s passed through the hands of 4-5 guys over the course of 3 years.  3 years is already at least a yellow flag in terms of iOS Development.  In my view, the only reason the same project should be allowed to live for 3 years is if you have older devices to support, or a massive userbase and a fat client architecture (making loss of data an issue).  For startups, you should always consider re-writing your Minimum Viable Product, as so many lessons are learned, so many pivots are made, so many corners are cut, to get you to where your codebase is today.  Cruft (look it up) is your biggest problem.

Poorly structured code will hurt your bottom line.  It becomes increasingly expensive to work with, and adding new features will not be easy, and the chances of introducing bugs will be high.  As much as one can talk about Test Driven Development (TDD), I’ve rarely heard of teams (in the startup world at least) that write tests, and if they do, they write them *after* the code has been written.  (This has proven to be the most expensive way to implement tests).  So, fine, the world is not perfect.  In these cases I would hope that if you are a developer reading this, you will at least put comments in your code and also NSAssert statements (the poor man’s sanity check / testing shortcut).

Let me now define what I mean by Hacker in the context of this post.  A Hacker is someone who may look good to any non-developer.  He gets the job done.  The code “works”.  He appears passionate as he types away in a frenzy, trying to make things ‘just right’.   The thing about a Hacker is that he may be self-taught and completely lack the principles of good software design.  He writes spaghetti code (that works).  He may say things like “I don’t need to put comments, the code should speak for itself.”  (If that’s true it is saying “Help me!” or “I’m taking hostages!” or “Your time now belongs to me!”).  But the worst thing about a Hacker on your team is that he will write code that is often a testament to every anti-pattern you have ever known, and to have to work with that person’s code is like being sabotaged before you can even begin.  Because to work with that code, you essentially have to rip out everything he’s done to make the codebase useable again.  So before you can begin to be awesome,  you have to weather the storm of management (who can’t possibly know your struggles) saying “I’m noticing progress is slow”, or “but it’s working now, what do you mean you need to rewrite it…?”

In short, a Hacker in charge of your codebase is basically signing a death warrant for your current codebase, or paying for a huge financial hangover after he’s gone.  A Hacker on your team can have some benefit (thinking outside the box, enthusiasm), but be wise and make sure he’s not in charge of architecture, and make sure you do code reviews.

Code Police – The Importance of Code Style Consistency

It’s not my intention to talk about which coding style is the best. Everyone has a specific style and their reasons for it.

I do recommend thinking about this topic, and to that aim there is a very interesting tool out there on the market called ObjectiveClean

I’ve enjoyed working with my colleagues on my current project and have a very friendly relationship with my boss. I do however have to chide him from time to time for not sticking to a clean coding style. I joke about being the Code Police. He jokes about keeping me on my toes.

There are certain style conventions that should however be adhered to for the following reasons:
– Conventions create consistency.
– Consistency allows you to make assumptions about how the code is written
– Assumptions allow you to refactor more easily.

What? If for example I have in my codebase the requirement that we write:

someString = @"SomeString";  // note the spaces between the equal sign

I can then easily find strings by searching for = @". You might not think that this is a big deal. You probably haven’t refactored a lot of code.

I spent over one hour refactoring some constants purely because they didn’t follow a standard. Imagine error codes defined like this:

static int const errNotConnected = -1;
static int const errWifiOff = -2;
static int const errFileIOError = 1;

2 absolutely horrible things result by trying to define error codes like this:

i) I provide no context for these error codes. I have no idea what class they relate to, what functionality.
ii) do a find and replace for these. if you put in a Project wide search term “err”… you are going to basically get thousands of results.

Now, the know-it-alls amongst you are going to say something snarky like “well, why don’t you just write a regular expression that will find exactly what you’re looking for?” The answer is practicality. Regex is a bit of Voodoo for most programmers and it’s not exactly pretty syntax despite how powerful it is.

You could just provide a context, and even better, pack these in an enum

typedef NS_ENUM(NSInteger, HSConnectionManagerErrorCode)
{
  HSConnectionManagerErrorCodeNotConnected = -1,
  HSConnectionManagerErrorCodeWifiOff = -2,
  HSConnectionManagerErrorCodeFileIOError = 1
};

From the name alone, I gain a few things:

i) I know which class it relates to
ii) I know what the error was all about
iii) Any time I’m coding I can just type in HSConnectionManager and Autocomplete will give me a list of the enums I’m looking for, so I don’t even need to go digging through header files.

Good habits allow us all to do our jobs more quickly, and make it easier to work with each other’s code. I highly recommend caring about the quality of your work. You can be proud of yourself and others will enjoy coding with you.

My Most Used Code Snippet in Xcode

It’s good to get in the habit of having good habits. 🙂

A lot of people write custom UIView code but then have trouble debugging a few things. Mostly pertaining to writing it to be initialized in code, then they initialize it in Interface Builder. As such, I just use the following snippet and it saves me a lot of boilerplate.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self configureView];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self configureView];
    }
    return self;
}

- (void)configureView
{
  // common initialization
}

That’s it for today.

Recipe: Enums to Strings and vice versa

(UPDATE: There’s a newer, companion post to this: HERE )

I’ve been finding it annoying sometimes when I have enums but then am debugging something and of course in the console, it’s not very human readable when it says something like:

Log> <MyObject: 0x234b3a> id: 23 type: 4

What is type 4?? Exactly. So let’s get something more readable in there: Here’s how you can easily get between the two:

// In your .h file, outside of an @interface declaration

typedef enum : NSInteger {
  MoodUnknown = -1,
  MoodDefault = 0,
  MoodExcited,
  MoodAngry,
  MoodHappy,
  MoodLazy
}Mood;

extern NSString * const MoodTypes[];

// conversion methods
extern NSString* NSStringFromMood(Mood m);
extern Mood MoodFromNSString(NSString *key);

Now then…

// in your .m file, outside (above) your @implmentation
NSString * const MoodTypes[] = {
  @"MoodDefault",
  @"MoodExcited",
  @"MoodAngry",
  @"MoodHappy",
  @"MoodLazy"
};

// UPDATE: why this?  Because if you have more than one of these arrays defined, using sizeof(MoodTypes) won't be correct.
static NSInteger const MoodTypesCount = 5;  

NSString* NSStringFromMood(Mood m)
{
  // in case you define an unknown mood as -1
  if(m < 0)
  {
    return @"MoodUnknown";
  }

  return MoodTypes[m];
}

Mood MoodFromNSString(NSString *key)
{
  if ([key isEqualToString:@"MoodUnknown"]) {
        return MoodUnknown;
    }

    for (int i = 0; i < MoodTypesCount - 1; i++) {
        if ([(NSString*)MoodTypes[i] isEqualToString: key]) {
            return (Mood)i;
        }
    }
    return MoodUnknown;
}

Then in your code, you’d have something like:

NSLog(@"Printing Object of Type: %@", NSStringFromMood(object.mood));