Tech

Better interaction between viewWillTransitionToSize and CGSize

1 min 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 viewWillTransition(to:with:) 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

1 min 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 few commands available:

$ mas list
446107677 Screens
407963104 Pixelmator
497799835 Xcode
Continue reading →

Easier hugging / compression handling

2 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(.required, forAxis: .vertical)
label.setContentHuggingResistancePriority(.defaultHigh, forAxis: .vertical)

So, let's extract them into a method, with default values as added bonus. We'll also use an enum, so we can have "intermediate" values as cases:

Continue reading →

TableViews, collectionViews and Swift enums

2 min 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 } // 1
  init?(rawValue: Int) // 2
 
  static var count: Int { get } // 3
 
}

This is a protocol that mimics an enum that conforms to Int: it has a rawValue of type Int (1), it has an initializer based on said rawValue (2), and it has a static var (3) that will be used to hold the total number of cases. And here's where extensions come into play:

extension Countable {
Continue reading →

Frame debugging on a device

2 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(50)) / 100,
    alpha: 1.0).CGColor
}
Continue reading →

Improving git log

2 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/'
}
Continue reading →

Working easier with tags

2 min read

One usual approach is to create an enum, so your tags are more expressive by having a name:

enum ViewTag: Int {
  case none
  case titleLabel
  case loginButton
}

Then tagging and retrieving views by tag will be safer, and easier to remember:

let container = UIView()
 
let titleLabel = UILabel()
container.addSubview(titleLabel)
titleLabel.tag = ViewTag.titleLabel.rawValue
 
let loginButton = UIButton(type: .Custom)
container.addSubview(loginButton)
loginButton.tag = ViewTag.loginButton.rawValue
Continue reading →

Creating a theme helper

2 min read

The standard approach for this would be something like this:

struct Theme {
  enum Color {
    case title
    case subtitle
    // [...]
    var color: UIColor {
      switch self {
      case .title: return UIColor.red
      case .subtitle: return UIColor.blue
      ...
      }
    }
  }
  
  enum Font {
  }
}

And using it throughout the app would look like this:

func customLabel(text: String, color uiColor: Theme.Color, font uiFont: Theme.Font) {
  [...]
  label.textColor = color.uiColor
  label.font = font.uiFont
  [...]
}
Continue reading →

LightPaper

45 sec read

I don't know why, but I've always seemed to be looking for the "perfect" Markdown editor - although I used a lot of really great ones, none really clicked with me.

Come in, LightPaper. Easy file access via the sidebar, multi-tabs, script assets, Jekyll Rendering, Math Rendering, MultiMarkdown or GitHub Flavored Markdown, a preference tab where you write CSS for extra customization on top of the usual CSS-based themes, and much more.

Continue reading →

PlugRocket

1 min read

It all started with this post by Joe for updating a plug-in from the terminal, which lead to this script for automating the process of updating all plug-ins.

Even though I could have created an Alfred workflow to easily run the script with a single command, I always wanted to start working on Mac apps, so this was a good opportunity to get my feet wet.

Continue reading →