Morten Bøgh

My personal blog.

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.

Octopress More Productive Than WordPress

Welcome to my new blog powered by Octopress.

This is a reboot of my blog and hopefully switching from WordPress to Octopress will make it easier for me to finish all the blog posts I have drafted in the old WordPress install. I find Octopress more suited for me since it is out of the browser and hopefully less distracting, so far I have only productive plugins installed for Sublime Text 2.
Using the tutorial Create a Blog With Octopress and Host It in Github Pages it was fairly easy to setup my blog on GitHub Pages. You can find the repository for this blog on mbogh.github.io.

Currently I am working on finalizing two posts. First one is a tutorial on integrating and using Unity as a component in your app rather than using Unity for every aspect of your app.
The second one is about symbolicating crash reports using LLDB which is useful when symbolicatecrash fails to do so.

I will add an About page when I find the time between changing diapers :)

Catch me on Twitter @mbogh