Morten Bøgh

My personal blog.

Hosts File Productivity Tip

I often find myself revisiting the same sites over and over again when faced with a tedious task. This is counter productive and is just prolonging the pain :)

So I have found it to be quite useful to simply block these sites locally, whenever I feel they become a problem.

To manage my hosts file I use Ghost which is easily installed from the terminal using gem install ghost. When a site is stealing too much of my time, I simply just block it by typing sudo ghost add facebook.com. Ghost will add the entry 127.0.0.1 facebook.com to /etc/hosts.

After 2 or 3 times getting the Safari Can’t Connect to the Server, you will stop using that site.

Use RVM With Octopress on OSX Yosemite

When the OS X Yosemite beta was released, I did a clean install of it on my MacBook Air. Time went by and then I had time to blog again, so I did the following:

Firstly cloned the repository from Github.

1
2
git clone git@github.com:mbogh/mbogh.github.io.git
cd mbogh.github.io

Next up is installing rbenv.

1
2
3
4
5
6
brew update
brew install rbenv
brew install ruby-build
rbenv install 1.9.3-p0
rbenv local 1.9.3-p0
rbenv rehash

Lastly install the gem bundler and install missing gems.

1
2
3
4
gem install bundler
rbenv rehash
bundle install
rake install

…booooom…

Then I ranted to my ruby-capable friend Markus, he laughed and said always use RVM and so I did.

1
2
3
4
5
6
\curl -sSL https://get.rvm.io | bash -s stable
rvm install 2.1-head
rvm use --default 2.1-head
gem install bundler
bundle install
rake install

And now you are seeing this post :)

Debugging Xcode Live Rendering

If you have experimented with Xcode Live Rendering, you have most likely seen errors like these:

error: IB Designables
1
Failed to update auto layout status: Interface Builder Cocoa Touch Tool crashed
error: IB Designables
1
Failed to render instance of ProfileAvatarView: The designables agent crashed

Placing breakpoints in prepareForInterfaceBuilder() will for obvious reasons never be hit. So it is frustrating to get these error messages, when you can not get a better explaination than something crashed.

prepareForInterfaceBuilder and Property Observers

If you are using the willSet and didSet property observers in combination with @IBInspectable and prepareForInterfaceBuilder() please notice that Xcode does things in this order:

  1. Calls init(frame:) on your class.
  2. Sets all the @IBInspectable properties with the values from Interface Builder
  3. Calls prepareForInterfaceBuilder() where you might take advantage of your @IBInspectable properties again.

This leads to confusion since the values you change in Interface Builder does not take effect as they are overriden by prepareForInterfaceBuilder().

A way around this, is to check whether the property has its default value or not:

MyView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import UIKit

@IBDesignable
class MyView: UIView {
    @IBOutlet weak var nameLabel: UILabel!

    @IBInspectable public var name: String = "" {
        didSet {
            self.nameLabel.text = name
        }
    }

    override func prepareForInterfaceBuilder() {
        if countElements(self.name) == 0 {
            self.name = "John Appleseed"
        }
    }
}

A bug report is in the making for Apple, will update this post when/if a response is posted.

And now back to Objective-C since my vacation has ended :)

Nib Designable - Xcode Live Rendering With Nibs Made Easy

In my previous post Xcode 6 Live Rendering From Nib, we ended up with CustomView a UIView subclass backed by a nib that is supported by Xcode Live Rendering.

CustomView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import UIKit

@IBDesignable
class CustomView: UIView {
    @IBOutlet weak var avatarImageView: UIImageView!
    @IBOutlet weak var titleLabel: UILabel!
    private weak var proxyView: CustomView?

    @IBInspectable public var title: String = "" {
        didSet {
            self.proxyView!.titleLabel.text = title
        }
    }

    @IBInspectable public var avatarImage: UIImage = UIImage() {
        didSet {
            let size = self.avatarImage.size
            let rect = CGRectMake(0, 0, size.width, size.height)
            UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
            var path = UIBezierPath(ovalInRect: rect)
            path.addClip()
            self.avatarImage.drawInRect(rect)

            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            self.proxyView!.avatarImageView.image = image
        }
    }

    init(frame: CGRect) {
        super.init(frame: frame)
        var view = self.loadNib()
        view.frame = self.bounds
        view.autoresizingMask = .FlexibleWidth | .FlexibleHeight
        self.proxyView = view
        self.addSubview(self.proxyView)
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }

    override func awakeAfterUsingCoder(aDecoder: NSCoder!) -> AnyObject! {
        if self.subviews.count == 0 {
            var view = self.loadNib()
            view.setTranslatesAutoresizingMaskIntoConstraints(false)
            let contraints = self.constraints()
            self.removeConstraints(contraints)
            view.addConstraints(contraints)
            view.proxyView = view
            return view
        }
        return self
    }

    private func loadNib() -> CustomView {
        let bundle = NSBundle(forClass: self.dynamicType)
        return bundle.loadNibNamed("CustomView", owner: nil, options: nil)[0] as CustomView
    }
}

This works well for a single custom view, but who only got one custom view, so let me introduce Nib Designable.

Xcode 6 Live Rendering From Nib

When Apple announced Xcode 6 at WWDC14, one feature in particular excited me namely Xcode Live Rendering. This means an end to all the empty white views in place for our custom views.

But as Apple states in What’s new in Xcode 6, it is intended for hand-written UI code.

Live rendering within Interface Builder displays your hand-written UI code within the design canvas, instantly reflecting changes you type in code.

This is unsatisfying for me, since I went all in on Interface Builder when Storyboards and Auto Layout were introduced. Also I find it strange that Apple has not made it easier to do custom views using nibs.

Swift Makes the Little Things More Simple

On monday 2014-06-02 Apple introduced a new scripting-style programming language called Swift. As an iOS developer I find this extremely interesting and looking forward to learn this new language and hopefully boost my productivity :)

Swift introduces a lot of nitfy new functions which makes your life as a developer much easier and hides away the boring details. Here is a showcase of map, reduce and filter.

Map

Objective-C
1
2
3
4
5
6
NSArray *names = @[@"John", @"Steve", @"Tim"];
NSMutableArray *namesTemporary = [NSMutableArray new];
names enumerateObjectsUsingBlock:^(NSString *name, NSUInteger idx, BOOL *stop) {
    [namesTemporary addObject:name.lowercaseString];
}];
names = [namesTemporary copy];
Swift
1
2
var names: String[] = ["John", "Steve", "Tim"]
names = names.map{ name in name.lowercaseString }
Swift (Alternative)
1
names = names.map{ $0.lowercaseString }

Empty Back Button on iOS7

On iOS7 the UINavigationBar features a nice little back arrow when used together with a UINavigationItem and/or UINavigationController.

But what if you wanted the back button text to disappear leaving the back arrow there by itself, turns out it is not as simple as you might expect.

Auto Layout and UIRotationGestureRecognizer + UIPinchGestureRecognizer

On a new project I recently joined, I was given the task to implement a feature which involved panning, zooming and rotating a UIImageView. A straightforward task and something I have done a few times before, so I went and wired up everything in the storyboard and found some old code for handling the three required actions. So far so good.