IBInspectable / IBDesignable
Show, don’t tell. Seeing is believing. A picture is worth a thousand emails words.
Whatever the cliché, replacing an interface that requires us to memorize and type with one we can see and manipulate can be an enormous improvement. Xcode 6 makes just such a substitution, building new interactions on top of old technologies. With IBInspectable
and IBDesignable
, it’s possible to build a custom interface for configuring your custom controls and have them rendered in real-time while designing your project.
IBInspectable
IBInspectable
properties provide new access to an old feature: user-defined runtime attributes. Currently accessible from the identity inspector, these attributes have been available since before Interface Builder was integrated into Xcode. They provide a powerful mechanism for configuring any key-value coded property of an instance in a NIB, XIB, or storyboard:
While powerful, runtime attributes can be cumbersome to work with. The key path, type, and value of an attribute need to be set on each instance, without any autocompletion or type hinting, which requires trips to the documentation or a custom subclass’s source code to double-check the settings. IBInspectable
properties solve this problem outright: in Xcode 6 you can now specify any property as inspectable and get a user interface built just for your custom class.
For example, these properties in a UIView
subclass update the backing layer with their values:
@IBInspectable var corner Radius: CGFloat = 0 {
did Set {
layer.corner Radius = corner Radius
layer.masks To Bounds = corner Radius > 0
}
}
@IBInspectable var border Width: CGFloat = 0 {
did Set {
layer.border Width = border Width
}
}
@IBInspectable var border Color: UIColor? {
did Set {
layer.border Color = border Color?.CGColor
}
}
Marked with @IBInspectable
(or IBInspectable
in Objective-C), they are easily editable in Interface Builder’s inspector panel. Note that Xcode goes the extra mile here—property names are converted from camel- to title-case and related names are grouped together:
Since inspectable properties are simply an interface on top of user-defined runtime attributes, the same list of types is supported: booleans, strings, and numbers (i.e., NSNumber
or any of the numeric value types), as well as CGPoint
, CGSize
, CGRect
, UIColor
, and NSRange
, adding UIImage
for good measure.
Those already familiar with runtime attributes will have noticed a bit of trickery in the example above.
UIColor
is the only color type supported, not theCGColor
native to a view’s backingCALayer
. Theborder
computed property maps theColor UIColor
(set via runtime attribute) to the layer’s requiredCGColor
.
Making Existing Types Inspectable
Built-in Cocoa types can also be extended to have inspectable properties beyond the ones already in Interface Builder’s attribute inspector. If you like rounded corners, you’ll love this UIView
extension:
extension UIView {
@IBInspectable var corner Radius: CGFloat {
get {
return layer.corner Radius
}
set {
layer.corner Radius = new Value
layer.masks To Bounds = new Value > 0
}
}
}
Presto! A configurable border radius on any UIView
you create.
IBDesignable
As if that weren’t enough, IBDesignable
custom views also debut in Xcode 6. When applied to a UIView
or NSView
subclass, the @IBDesignable
designation lets Interface Builder know that it should render the view directly in the canvas. This allows seeing how your custom views will appear without building and running your app after each change.
To mark a custom view as IBDesignable
, prefix the class name with @IBDesignable
(or the IB_DESIGNABLE
macro in Objective-C). Your initializers, layout, and drawing methods will be used to render your custom view right on the canvas:
@IBDesignable
class My Custom View: UIView {
...
}
The time-savings from this feature can’t be overstated. Combined with IBInspectable
properties, a designer or developer can easily tweak the rendering of a custom control to get the exact result she wants. Any changes, whether made in code or the attribute inspector, are immediately rendered on the canvas.
Moreover, any problems can be debugged without compiling and running the whole project. To kick off a debugging session right in place, simply set a breakpoint in your code, select the view in Interface Builder, and choose Editor ➔ Debug Selected Views.
Since the custom view won’t have the full context of your app when rendered in Interface Builder, you may need to generate mock data for display, such as a default user profile image or generic weather data. There are two ways to add code for this special context:
prepare
: This method compiles with the rest of your code but is only executed when your view is being prepared for display in Interface Builder.For Interface Builder()
TARGET_INTERFACE_BUILDER
: The#if TARGET_INTERFACE_BUILDER
preprocessor macro will work in either Objective-C or Swift to conditionally compile the right code for the situation:
#if !TARGET_INTERFACE_BUILDER // this code will run in the app itself #else // this code will execute only in IB #endif
IBCalculatorConstructorSet
What can you create with a combination of IBInspectable
attributes in your IBDesignable
custom view? As an example, let’s update an old classic from Apple folklore: the “Steve Jobs Roll Your Own Calculator Construction Set,” Xcode 6-style (gist):
That was almost a thousand words—let’s see some more pictures. What are you creating with these powerful new tools? Tweet an image of your IBInspectable
or IBDesignable
creations with the hashtag #IBInspectable
—we can all learn from seeing what’s possible.