NSDate operators

:  ~ 40 sec read

I personally find this a bit of a mouthful, especially if you have to type it a lot:

if someDate.compare(otherDate) == .OrderedAscending {
  // Do stuff
}

But we can have a few operators to make our lives a bit easier:

func <(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedAscending
}
func <=(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs < rhs || lhs == rhs
}

func >(lhs: […]

Continue reading →

Detecting retain cycles and improved logging

:  ~ 40 sec read

I think adding a deinit method, with a print statement everywhere is a decent first barrier against retain cycles:

deinit {
  print("Object X has been deinitialized.")
}

This way, if you expect object x to deinit at some point, but it doesn't, you at least know you need to start searching.

Now, for the improved printing, to make this a bit cleaner and easier:

func customPrint(
  object: Any,
  function: String = #function,
  _ file: String = #file,
  _ line: UInt = #line) {
  #if DEBUG […]

Continue reading →

Improving UIFont workflow

:  ~ 40 sec read

Usually an app has fonts with well defined purposes. So why not let enums make our lives easier, a little bit? First, a couple of them, to define our font families and weights:

struct Font {
  private enum Family: String {
    case AvenirNext
    case ProximaNova
  }

  private enum Weight: String {
    case Regular
    case Medium
    case DemiBold
    case Bold
  }
}

Then a method to easily create fonts:

private static func baseFont(family family: Family, size: CGFloat, weight: Weight = .Regular, italic: Bool = false) -> UIFont { […]

Continue reading →

Setting variables with tuples, switches and closures

:  ~ 1 min read

Let's say we have a custom UILabel, which in turn has several types; maybe a StatusLabel that can be of type sold out and expired. The label would have several common properties, but each type would have something specific. How can we go about this?

class StatusLabel: UILabel {
  enum Type {
    case SoldOut
    case Expired
  }

  init(type: Type) {
    super.init(frame: .zero)

    font = UIFont.commonFont()
    layer.cornerRadius = 4
    textAlignment = .Center
    translatesAutoresizingMaskIntoConstraints = false
  }
}

We now covered […]


Continue reading →

Better interaction between viewWillTransitionToSize and CGSize

:  ~ 25 sec read

Instead of checking if size.width > size.height, we can have three handy CGSize extensions:

extension CGSize {
  var isCompact: Bool { return height > width + delta }
  var isWide: Bool { return width > height + delta }
  var isSquare: Bool { return abs(width - height) < delta } 
}

For usage within viewWillTransitionToSize I don't think the delta will be really needed, but if we want to use these properties for our own custom views, it might come in handy. Modify its value to fit your own needs, of course.

The MAS, updates and the CLI

:  ~ 52 seconds read

I've had problems with stuck updates, or slow downloads with the MAS for as far as I can remember. softwareupdate never really was of much help, using MAS' Debug menu neither, nor killing softwareupdate related processes.

Yesterday I found the answer to all of this: a gem for manipulating the MAS from the CLI. It uses native APIs, from login (the MAS login pops up), to downloading files (you can even start an update with the MAS and finish it on the CLI - the download files are the same). And you also get a nice, little progress bar.

A […]


Continue reading →

Easier hugging / compression handling

:  ~ 1 min read

I'm pretty sure this won't suit all cases, but, usually, a label / button should highly resist being vertically shrunk more than its intrinsic size. On the other hand, we won't always mind if it grows larger than its intrinsic size, but we'd like to avoid it, if possible.

I, personally, find this a bit of a mouthful:

label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.setContentHuggingResistancePriority(UILayoutPriorityDefaultHigh, forAxis: .Vertical)

So, let's extract them into a method, with default values, as added bonus, and use an enum, as extra […]


Continue reading →

TableViews, collectionViews and Swift enums

:  ~ 40 sec read

I talked about how we can have a safer and cleaner tableView / collectionView section handling, but we can improve it even further, with protocol extensions:

protocol Countable {
  var rawValue: Int { get }
  static var count: Int { get }
  init?(rawValue: Int)
}
extension Countable {
  static var count: Int {
    var max = 0
    while let _ = self.init(rawValue: max) { max += 1 }
    return max
  }
}

Then, when we create an Int extension, we have the number of cases, out of […]


Continue reading →

Frame debugging on a device

:  ~ 1 min read

There's this handy feature, Debug -> View Debugging -> Show View Frames, which, if turned on, draws borders around views. The sad part is that it only works on the simulator. But we can (somewhat) easily simulate its behavior.

First, we create a helper method that does the coloring:

func activateFramesDebug() {
  guard debugFrames else { return }
  layer.borderWidth = 1
  layer.borderColor = UIColor(
    hue: CGFloat(arc4random_uniform(100_000)) / 100_000,
    saturation: CGFloat(arc4random_uniform(100_000)) / 100_000,
    brightness: 0.5 + CGFloat(arc4random_uniform […]

Continue reading →

Improving git log

:  ~ 1 min read

We can already use --graph and --decorate to get a pretty, colored commit tree, but we can create a function for less typing, more flexibility and more info:

git_branch() {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
}
# Short for git decorated log
gdl() {
  branches=''
  if [ -n "$1" ] && [ -n "$2" ]; then
    branches=$1..$2
  elif [ -n "$1" ]; then
    if [ $1 == "keyword" ]; then
      branches="$(git_branch)" […]

Continue reading →