UILabel when inactive, UISlider when active

I’m working on a new app and I’m trying to keep the interface minimal in terms of screen elements.  Also, design-wise I’m a huge fan of finding ways to only use space *when* you need it, and finding novel ways to conceal elements that you don’t need (when you don’t need them).  On the flipside, one should also be conscious of hiding too much, thus alienating some users who don’t immediately have a good sense for such things.  That addresses the need for good onboarding but that’s a longer discussion.

So I thought, (the new app is a music player), “it’s not often you need to seek to a certain time in the song, so why does this element get to take up so much space?”

Since my app’s UX generally involves interacting with labels, I thought it would be interesting to hide a slider behind a label, but when you interact with it, it’s the underlying control that becomes active.

I think I should just show the code.  The key is in how one overrides the method -hitTest:withEvent:  Because of that, this solution is very flexible in terms of what kind of UISlider you use, and what kind of UILabel you use.  It’s the technique worth noting because it could have a few applications.

Shoot me a message if you don’t quite understand why this does what it does, or why a different approach might / might not work for you.

(Oh yeah, the assumption is that the subviews are pinned to their parent’s edges… i.e. same frame.size)

/  LabelScrubber.swift
//  LabelScrubber
//  Created by Stephen O'Connor on 03.11.20.
//  Copyright © 2020 HomeTeam Software. All rights reserved.

import UIKit

class LabelScrubber: UIView {

    let showDelayShort = 0.7
    let showDelayLong = 1.2
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var slider: UISlider!
    var labelTimer: Timer?
    /// this gets called on a touch down, so in other words, at the beginning of an interaction
    /// but you tell it which view you want to be 'the view' for the interaction.
    /// super cool; so you can override and say it's the slider that matters
    /// and thus you'll interact with that.
    /// nice though that we can make preparations before that interaction,
    /// like snapping the slider to where your touch is!
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if self.bounds.contains(point) {
            self.slider.isHidden = false
            self.label.isHidden = true
            let percentX = point.x / self.bounds.size.width
            let targetValue = self.slider.minimumValue + Float(percentX) * (self.slider.maximumValue - self.slider.minimumValue)
            self.slider.setValue(targetValue, animated: true)
            showLabel(after: showDelayLong)
            return self.slider
        return super.hitTest(point, with: event)
    override var intrinsicContentSize: CGSize {
        return label.intrinsicContentSize
    override init(frame: CGRect) {
        super.init(frame: frame)
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    override func awakeFromNib() {
    private func commonInit() {
        self.label.isUserInteractionEnabled = false
        self.label.isHidden = false
        self.slider.isHidden = true
        self.slider.addTarget(self, action: #selector(tracking(_:)), for: .touchDown)
        self.slider.addTarget(self, action: #selector(tracking(_:)), for: .valueChanged)
        self.slider.addTarget(self, action: #selector(finishedTracking(_:)), for: .touchUpInside)
        self.slider.addTarget(self, action: #selector(finishedTracking(_:)), for: .touchUpOutside)
    func finishedTracking(_ slider: UISlider) {
        showLabel(after: showDelayShort)
    func tracking(_ slider: UISlider) {
    private func showLabel(after delay: TimeInterval) {
        labelTimer = Timer.scheduledTimer(withTimeInterval: delay,
                                          repeats: false,
            { [weak self] (_) in
    func invalidateShowTimer() {
    func returnToDefaultState(duration: TimeInterval = 0.3) {

        self.slider?.alpha = 1.0
        UIView.animate(withDuration: duration,
                       animations: {
                        //self.label?.alpha = 1.0
                        self.slider?.alpha = 0.0
        }) { [weak self] (_) in
            self?.label?.isHidden = false
            self?.slider?.isHidden = true
            self?.slider?.alpha = 1.0

GDPR Compliance and Analytics

This post is more of a conceptual brainstorm about GDPR and still being able to acquire useful analytics data.

If I were to sum up the GDPR, I basically take it to mean that you cannot store/track data about your user without their consent, AND they have the right to be forgotten… i.e. they should be in control of their own data.  This basically means don’t track usage events using a user identifier (on iOS the venerable identifierForVendor property), as this would constitute gathering data about a person that can be inferred via this identifier.

If you can convince your user to opt-in, then great.  Business as usual just with some provisions to be able to delete any data they no longer want you to have/use.  But is there a way to still gather information about App usage without someone’s consent while still obfuscating who actually did the things you’re trying to track?  My understanding is that you can gather all the data you want so long as it’s not possible to trace that back to the user itself.

My thoughts are that if you as an analytics person are able to relax your requirements somewhat, I think it could be possible.  If you as an analytics person don’t need real-time updates on how your users have been using your app, but still want all the same insights, I think it’s still achievable…. if you have patience.

I think the solution is to keep all usage tracking on the device itself, then say once a month you upload it all in one go to some custom API endpoint that would parse all that data into usage stats, all without some user identifier.  The semantics of that are “There is a user – we don’t know who – who used the app in the following ways last month.”  Then you can see funnels.  Then you can see retention.  Then you can see all of those things over a time frame that is useful.

Currently, if we uploaded each and every event as they happened, you’d have no way to connect all those events to a user.  If you upload all of those in one go, with timestamps, you can still process all this data and get a picture of what a user does in a specific amount of time without caring about who it was, specifically.

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>

@interface HSStretchyHeaderTableView : UITableView

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


And now the .m file:

#import "HSStretchyHeaderTableView.h"

@interface HSStretchyHeaderTableView()
    CGFloat _headerViewHeight;

@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;


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>

@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;


And the .m file

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

#import "HSProgressView.h"

@interface HSProgressView()

+ (NSArray*)customLayerProperties;


@interface _HSProgressViewLayer : CALayer

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


@implementation _HSProgressViewLayer

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

+ (BOOL)needsDisplayForKey:(NSString *)key
    for (NSString *propertyName in [HSProgressView customLayerProperties]) {
        if ([key isEqualToString:propertyName]) {
            return YES;
    return [super needsDisplayForKey:key];

// 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;
    progress = [self.presentationLayer progressValue];
    progress = [self progressValue];
    //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;


static NSArray *HSProgressViewLayerProperties = nil;

@implementation HSProgressView

+ (Class)layerClass
    return [_HSProgressViewLayer class];
+ (NSArray*)customLayerProperties
    if (!HSProgressViewLayerProperties) {
        HSProgressViewLayerProperties = @[
    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];
    [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

- (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.


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,

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[] = {

// 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));

UITableView or UICollectionView Lazy Registration – dispatch_once

(UPDATE:  Don’t do this.  See discussion at the end)

Starting with iOS 6, UIKit added the following family of methods to UITableView and UICollectionView:

// UICollectionView
- (void)registerClass:(Class)aClass forCellWithReuseIdentifier:(NSString*)someIdentifier;

// UITableView  
- (void)registerClass:(Class)aClass forCellReuseIdentifier:(NSString*)someIdentifier;

Which makes it convenient to get a cell when you need one, without too much extra code. Doing it this way also ensures that you are designing your custom cells in their own subclass, rather than adding subviews to a view in a controller class. (I really like how Apple tries to make you become a better programmer by forcing you to write cleaner code and separate your concerns. See Why I DO use Interface Builder for more on that).

What I find sometimes annoying is forgetting to register this class somewhere (likely viewDidLoad), and it crashes at runtime. I also hate having to jump around code too much if it makes it less readable, so lately I’ve been using the following approach, which takes advantage of the pattern used when creating singletons; use the dispatch_once approach:

// in tableView:cellForRowAtIndexPath:

    static NSString *CellIdentifier = @"MyCell";
    static dispatch_once_t myCellOnceToken;  // define a variable name here that is specific to the context
    dispatch_once(&myCellOnceToken, ^{
        [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];

Maybe this approach will work well for you as well. Currently I’m not aware of the potential dangers of this, if there are any. Have to admit my knowledge of gcd up until this point has had a lot to do with recipes found on stack overflow.

UPDATE – There are dangers associated with this, so DON’T DO THIS. If you execute a dispatch_once block, but your collectionView is dealloc’d for whatever reason, the next time the newly created _different_ collectionView needs a cell, it won’t be registered.

SO, Moral of the Story:  Don’t forget to register your classes/nibs.  And do that in viewDidLoad, or somewhere right after you UICollectionView or UITableView is created.