Review of Training Guide: Programming in HTML5 with JavaScript and CSS3

OK so it’s been a while since my last review, and I’ve finally picked up a copy of Training Guide: Programming in HTML5 with Javascript and CSS3 | Glenn Johnson. The book from the onset was focused on using Microsoft technologies and tools, to illustrate platform-neutral concepts, which was an issue for me, honestly. The book itself is very well structured, but it’s primary aim is to build windows 8-focused windows applications. With that caveat in mind, if the book still fits your workflow and plans, continue reading… The book kicks-off by introducing you to the tools of the trade for learning to program on the Microsoft platform, Visual Studio, with some hints on moulding a workable environment for you to get set-up. The following chapters introduce basic HTML5 concepts, which works for me regardless of whether I program on a Mac or Windows, and then some javascript concepts and then in chapter 4, we get to some CSS3. The later was quite a useful chapter for me, as it brought out a lot of concepts I hadn’t used before, since CSS3 wasn’t something I focused on as I am not a seasoned Web Designer.

Chapter 5 and 6 begin to dive deeper into more advanced HTML5 and Javascript/JQuery, going into new markups that the author wants to have covered, before Chapter 7 builds on top of that, with forms, using javascript/JQuery. Chapter 8 was one of my favourite chapters, as it went into web services, using Node.JS and REST, and I do plan on reading a dedicated NodeJS book hopefully soon, this chapter certain whet my appetite.

The two chapters following discussed Ajax and general asynchronous logic more, such as working with web sockets. The remaining chapters, from 11 onwards went back to discussing HTML5 concepts, from location-awareness, drawing, drag-and-drop, local data storage and finally working with offline applications.

The book in total touches on a lot of concepts, and whilst this book will not make you an expert in either one topic, it provides a strong general overview. It is focused on beginners to web development, and whilst I would have liked this book to be more platform-agnostic, especially since it used very heavily community-pushed technologies like NodeJS, I appreciated the strength of the content of this book, the fact it kept concepts in context, in order for you to understand the relevance of such technologies. A compelling book, and for aspiring web developers, this book puts you in the right direction.

Concise: 5

Level: 4

Prior Knowledge: For aspiring web developers. A bit of .NET knowledge is required for one chapter, but you can pick the chapters that suit your aspirations and skillset.

My rating : 4.5

Author: Glenn Johnson

TitleTraining Guide: Programming in HTML5 with Javascript and CSS3

Publisher: O’Reilly Media

Year: JANUARY 2013

Working with auto layouts in iOS 7


iOS_7_feast_3iOS_7_feast_3

A Primer on working with auto-layouts that I thought I’d include, as it’s always something handy to come back to. Thanks to the great guys at RayWemderlich for the tutorial.

Have you ever been frustrated trying to make your apps look good in both portrait and landscape orientation? Is making screen layouts that support both the iPhone and iPad driving you to the brink of madness? Despair no longer, I bring you good news!

It’s not hard to design a user interface for a screen that is always guaranteed to be the same size, but if the screen’s frame can change, the positions and sizes of your UI elements also have to adapt to fit into these new dimensions.

Until now, if your designs were reasonably complex, you had to write a lot of code to support such adaptive layouts. You will be glad to hear that this is no longer the case – iOS 6 brings an awesome new feature to the iPhone and iPad: Auto Layout. Xcode 5 and iOS 7 make it even better! If you tried Auto Layout in Xcode 4 and gave up, then you really should give Xcode 5 another chance.

Not only does Auto Layout makes it easy to support different screen sizes in your apps, as a bonus it also makes internationalization almost trivial. You no longer have to make new nibs or storyboards for every language that you wish to support, and this includes right-to-left languages such as Hebrew or Arabic.

This Auto Layout tutorial shows you how to get started with Auto Layout using Interface Builder. In iOS 6 by Tutorials, we take this tutorial even further, and then have an entirely new chapter that builds on this knowledge and shows you how to unleash the full power of Auto Layout via code.

Note: We are in the process of updating all of the chapters in iOS 6 by Tutorials to iOS 7 – and this is a sneak preview of that update! When we’re done, the update will be a free download to all iOS 6 by Tutorials PDF customers.

So grab a snack and your favorite caffeinated beverage, and get ready to become an Auto Layout master!

The problem with springs and struts

You are no doubt familiar with autosizing masks – also known as the “springs and struts” model. The autosizing mask determines what happens to a view when its superview changes size. Does it have flexible or fixed margins (the struts), and what happens to its width and height (the springs)?

For example, with a flexible width the view will become proportionally wider if the superview also becomes wider. And with a fixed right margin, the view’s right edge will always stick to the superview’s right edge.

The autosizing system works well for simple cases, but it quickly breaks down when your layouts become more intricate. Let’s look at an example where springs and struts simply don’t cut it.

Open Xcode 5 and create a new iPhone project based on the Single View Application template. Call the app “StrutsProblem”:

Project options

Click on Main.storyboard to open it in Interface Builder. Before you do anything else, first disable Auto Layout for this storyboard. You do that in the File inspector, the first of the six tabs:

Disable autolayout

Uncheck the Use Autolayout box. Now the storyboard uses the old struts-and-springs model.

Note: Any new nib or storyboard files that you create with Xcode 4.5 or better will have Auto Layout activated by default. Because Auto Layout is an iOS 6-and-up feature only, if you want to use the latest Xcode to make apps that are compatible with iOS 5, you need to disable Auto Layout on any new nibs or storyboard files by unchecking the “Use Autolayout” checkbox.

Drag three new views onto the main view and line them up like this:

Design of the StrutsProblem app

For clarity, give each view its own color so that you can see which is which.

Each view is inset 20 points from the window’s borders; the padding between the views is also 20 points. The bottom view is 280 points wide and the two views on top are both 130 points wide. All views are 254 points high.

Run the app on the iPhone Retina 4-inch simulator and rotate the simulator to landscape. That will make the app look like this, not quite what I had in mind:

Landscape looks bad

Note: You can rotate the simulator using the HardwareRotate Left and Rotate Right menu options, or by holding down ⌘ on your keyboard and tapping the left or right arrow keys.

Instead, you want the app to look like this in landscape:

What landscape is supposed to look like

Obviously, the autosizing masks for all three views leave a little something to be desired. Change the autosizing settings for the top-left view to:

Autosizing top-left view

This makes the view stick to the top and left edges (but not the bottom and right edges), and resizes it both horizontally and vertically when the superview changes its size.

Similarly, change the autosizing settings for the top-right view:

Autosizing top-right view

And for the bottom view:

Autosizing bottom view

Run the app again and rotate to landscape. It should now look like this:

Landscape still looks bad

Close, but not quite. The padding between the views is not correct. Another way of looking at it is that the sizes of the views are not 100% right. The problem is that the autosizing masks tell the views to resize when the superview resizes, but there is no way to tell them by how much they should resize.

You can play with the autosizing masks – for example, change the flexible width and height settings (the “springs”) – but you won’t get it to look exactly right with a 20-point gap between the three views.

Why?!?!?

To solve this layout problem with the springs and struts method, unfortunately you will have to write some code.

UIKit sends several messages to your view controllers before, during and after rotating the user interface. You can intercept these messages to make changes to the layout of your UI. Typically you would overrideviewWillLayoutSubviews to change the frames of any views that need to be rearranged.

Before you can do that, you first have to make outlet properties to refer to the views to be arranged.

Switch to the Assistant Editor mode (middle button on the Editor toolset on the Xcode toolbar) and Ctrl-drag from each of the three views onto ViewController.m:

Ctrl-drag outlet property

Connect the views to these three properties, respectively:

@property (weak, nonatomic) IBOutlet UIView *topLeftView;
@property (weak, nonatomic) IBOutlet UIView *topRightView;
@property (weak, nonatomic) IBOutlet UIView *bottomView;

Add the following code to ViewController.m:

- (void)viewWillLayoutSubviews
{
    if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
    {
        CGRect rect = self.topLeftView.frame;
        rect.size.width = 254;
        rect.size.height = 130;
        self.topLeftView.frame = rect;

        rect = self.topRightView.frame;
        rect.origin.x = 294;
        rect.size.width = 254;
        rect.size.height = 130;
        self.topRightView.frame = rect;

        rect = self.bottomView.frame;
        rect.origin.y = 170;
        rect.size.width = 528;
        rect.size.height = 130;
        self.bottomView.frame = rect;
    }
    else
    {
        CGRect rect = self.topLeftView.frame;
        rect.size.width = 130;
        rect.size.height = 254;
        self.topLeftView.frame = rect;

        rect = self.topRightView.frame;
        rect.origin.x = 170;
        rect.size.width = 130;
        rect.size.height = 254;
        self.topRightView.frame = rect;

        rect = self.bottomView.frame;
        rect.origin.y = 295;
        rect.size.width = 280;
        rect.size.height = 254;
        self.bottomView.frame = rect;
    }
}

This callback occurs when the view controller is rotating to a new orientation. It looks at the orientation the view controller has rotated to and resizes the views appropriately – in this case with hardcoded offsets based on the known screen dimensions of the iPhone. This callback occurs within an animation block, so the changes in size will animate.

Don’t run the app just yet. First you have to restore the autosizing masks of all three views to the following, or the autosizing mechanism will clash with the positions and sizes you set on the views in viewWillLayoutSubviews:

Autosizing off

That should do it. Run the app and flip to landscape. Now the views line up nicely. Flip back to portrait and verify that everything looks good there as well.

It works, but that was a lot of code you had to write for a layout that is pretty simple. Imagine the effort it takes for layouts that are truly complex, especially dynamic ones where the individual views change size, or the number of subviews isn’t fixed.

Now try running the app on the 3.5-inch simulator. Whoops. The positions and sizes of the views are wrong because the hardcoded coordinates in viewWillLayoutSubviews are based on the dimensions of the 4-inch phone (320×568 instead of 320×480). You could add another if-statement that checks the screen size and uses a different set of coordinates, but you can see that this approach is becoming unworkable quickly.

There must be another way

Note: Another approach you can take is to make separate nibs for the portrait and landscape orientations. When the device rotates you load the views from the other nib and swap out the existing ones. But this is still a lot of work and it adds the trouble of having to maintain two nibs instead of one. This approach is quite impractical when you’re using storyboards instead of nibs.

Auto Layout to the rescue!

You will now see how to accomplish this same effect with Auto Layout. First, remove viewWillLayoutSubviews from ViewController.m, because you’re going to do this without writing any code.

Select Main.storyboard and in the File inspector panel, check the Use Autolayout box to enable Auto Layout for this storyboard file:

Enable autolayout

Note: Auto Layout is always enabled for the entire nib or storyboard file. All the views inside that nib or storyboard will use Auto Layout if you check that box.

Run the app and rotate to landscape. It now looks like this:

Landscape looks bad with Auto Layout

Let’s put Auto Layout into action. Hold down the ⌘ key while you click on the two views on the top (the green and yellow ones), so that both are selected. From Xcode’s Editor menu, select PinWidths Equally:

Pin widths equally

Select the same two views again and choose EditorPinHorizontal Spacing. (Even though the two views appear selected after you carry out the first Pin action, do note that they are in a special layout relationship display mode. So you do have to reselect the two views.)

The storyboard now looks like this:

Storyboard after adding horizontal space constraint

The orange “T-bar” shaped things represent the constraints between the views. So far you added two constraints: an Equal Widths constraint on both views (represented by the bars with the equals signs) and a Horizontal Space constraint that sits between the two views. Constraints express relationships between views and they are the primary tool you use to build layouts using Auto Layout. It might look a bit scary, but it is actually quite straightforward once you learn what it all means.

To continue building the layout for this screen, perform the following steps. Each step adds more orange T-bars.

For the view on the left, choose from the EditorPin menu:

  • Top Space to Superview
  • Leading Space to Superview

For the view on the right, choose:

  • Top Space to Superview
  • Trailing Space to Superview

And for the big view at the bottom:

  • Leading Space to Superview
  • Trailing Space to Superview
  • Bottom Space to Superview

You should now have the following constraints:

Constraints after performing the steps

Notice that the T-bars are still orange. That means your layout is incomplete; Auto Layout does not have enough constraints to calculate the positions and sizes of the views. The solution is to add more constraints until they turn blue.

Hold down ⌘ and select all three views. From the Editor menu, choose PinHeights Equally.

Now select the top-left corner view and the bottom view (using ⌘ as before), and choose EditorPinVertical Spacing.

Interface Builder should show something like this:

The constraints are valid

The T-bars have become blue. Auto Layout now has enough information to calculate a valid layout. It looks a bit messy but that’s because the Equal Widths and Equal Heights constraints take up a lot of room.

Run the app and… voila, everything looks good again, all without writing a single line of code! It also doesn’t matter which simulator you run this on; the layout works fine on 3.5-inch as well as 4-inch devices.

Landscape now looks good with Auto Layout

Cool, but what exactly did you do here? Rather than requiring you to hard-code how big your views are and where they are positioned, Auto Layout lets you express how the views in your layout relate to each other.

You have put the following relationships – what is known as constraints – into the layout:

  • The top-left and top-right views always have the same width (that was the first pin widths equally command).
  • There is a 20-point horizontal padding between the top-left and top-right views (that was the pin horizontal spacing).
  • All the views always have the same height (the pin heights equally command).
  • There is a 20-point vertical padding between the two views on top and the one at the bottom (the pin vertical spacing).
  • There is a 20-point margin between the views and the edges of the screen (the top, bottom, leading, and trailing space to superview constraints).

And that is enough to express to Auto Layout where it should place the views and how it should behave when the size of the screen changes.

Well done

You can see all your constraints in the Document Outline on the left. The section named Constraints was added when you enabled Auto Layout for the storyboard. (If you don’t see the outline pane, then click the arrow button at the bottom of the Interface Builder window.)

If you click on a constraint in the Document Outline, Interface Builder will highlight where it sits on the view by drawing a white outline around the constraint and adding a shadow to it so that it stands out:

Selected constraint

Constraints are real objects (of class NSLayoutConstraint) and they also have attributes. For example, select the constraint that creates the padding between the two top views (it is named “Horizontal Space (20)” but be sure to pick the correct one) and then switch to the Attributes inspector. There you can change the size of the margin by editing the Constant field.

Constraint attributes

Set it to 100 and run the app again. Now the margin is a lot wider:

There is a wider margin between the views

Auto Layout is a lot more expressive than springs and struts when it comes to describing the views in your apps. In the rest of this tutorial, you will learn all about constraints and how to apply them in Interface Builder to make different kinds of layouts.

How Auto Layout works

As you’ve seen in the test drive above, the basic tool in Auto Layout is the constraint. A constraint describes a geometric relationship between two views. For example, you might have a constraint that says:

“The right edge of label A is connected to the left edge of button B with 20 points of empty space between them.”

Auto Layout takes all of these constraints and does some mathematics to calculate the ideal positions and sizes of all your views. You no longer have to set the frames of your views yourself – Auto Layout does that for you, entirely based on the constraints you have set on those views.

Before Auto Layout, you always had to hard-code the frames of your views, either by placing them at specific coordinates in Interface Builder, by passing a rectangle into initWithFrame:, or by setting the view’sframe, bounds or center properties.

For the app that you just made, you specifically set the frames to:

Struts coordinates

You also set autosizing masks on each of these views:

Struts autosizing masks

That is no longer how you should think of your screen designs. With Auto Layout, all you need to do is this:

Auto Layout instead of struts

The sizes and positions of the views are no longer important; only the constraints matter. Of course, when you drag a new button or label on to the canvas it will have a certain size and you will drop it at a certain position, but that is only a design aid that you use to tell Interface Builder where to put the constraints.

Designing like you mean it

The big advantage of using constraints is that you no longer have to fiddle with coordinates to get your views to appear in the proper places. Instead, you can describe to Auto Layout how the views are related to each other and Auto Layout will do all the hard work for you. This is called designing by intent.

When you design by intent, you’re expressing what you want to accomplish but not necessarily how it should be accomplished. Instead of saying: “the button’s top-left corner is at coordinates (20, 230)”, you now say:

“The button is centered vertically in its superview, and it is placed at a fixed distance from the left edge of the superview.”

Using this description, Auto Layout can automatically calculate where your button should appear, no matter how big or small that superview is.

Other examples of designing with intent (and Auto Layout can handle all of these instructions):

“These two text fields should always be the same size.”
“These two buttons should always move together.”
“These four labels should always be right-aligned.”

This makes the design of your user interfaces much more descriptive. You simply define the constraints, and the system calculates the frames for you automatically.

You saw in the first section that even a layout with just a few views needs quite a bit of work to layout properly in both orientations. With Auto Layout you can skip all that effort. If you set up your constraints properly, then the layout should work without any changes in both portrait and landscape.

Another important benefit of using Auto Layout is internationalization. Text in German, for example, is infamous for being very long and getting it to fit into your labels can be a headache. Again, Auto Layout takes all this work out of your hands, because it can automatically resize your labels based on the content they need to display – and have everything else adapt with constraints.

Adding support for German, French, or any other language is now simply a matter of setting up your constraints, translating the text, and… that’s it!

French

The best way to get the hang of Auto Layout is to play with it, so that’s exactly what you will do in the rest of this tutorial.

Note: Auto Layout is not just useful for rotation; it can also easily scale your UI up and down to accommodate different screen sizes. It is no coincidence that this technology was added to iOS at the same time that the iPhone 5 and its taller screen came out! Auto Layout makes it a lot easier to stretch your apps’ user interfaces to fill up that extra vertical space on the iPhone 5. And with Dynamic Type in iOS 7, Auto Layout has become even more important. Users can now change the global text size setting — with Auto Layout this is easy to support in your own apps.

Courting constraints

Close your current project and create a new iPhone project using the Single View Application template. Name it “Constraints”. Any new projects that you create with Xcode 5 automatically assume that you will be using Auto Layout, so you do not need to do anything special to enable it.

Click on Main.storyboard to open Interface Builder. Drag a new Button onto the canvas. Notice that while you’re dragging, dashed blue lines appear. These lines are known as the guides:

Guides

There are guides around the margins of the screen, as well as in the center:

Other examples of guides

If you have used Interface Builder before, then you have no doubt seen these guides. They are helpful hints that make it easier to align stuff.

In Xcode 4 with Auto Layout enabled, the guides had a different purpose. You still used them for alignment, but they also told you where the new constraints would go. If you dropped the button in the top-left corner against the blue guides, the storyboard in Xcode 4 would look like this:

Button with guides

There are two blue thingies attached to the button. These T-bar shaped objects are the constraints. No matter where you placed your UI controls in Xcode 4′s Interface Builder, they always were given valid constraints. That sounded like a good idea in theory but in practice it made Auto Layout incredibly hard to use from Interface Builder.

Fortunately, that has changed for the better with Xcode 5. After you drop the button into the canvas, there are no T-bars to be seen:

There are no constraints on the button

Notice that there is no Constraints section in the Document Outline pane either. Conclusion: this button does not have any constraints set on it.

But how can this work? You just learned that Auto Layout always needs enough constraints to determine the size and position of all the views, but here you have no constraints at all. Surely this is an incomplete layout?

This is where Xcode 5 is a big improvement over Xcode 4: it no longer forces you to always have a valid layout.

Note: It is a bad idea to run an app with an invalid layout because Auto Layout cannot properly compute where the views should go. Either the positions of the views will be unpredictable (not enough constraints) or the app will crash (too many constraints). Yikes!

Xcode 4 tried to prevent this from happening by making sure there were always exactly enough constraints to create a valid layout. Unfortunately, it often did this by removing your own constraints and replacing them by constraints you did not actually want. That could be very frustrating and many developers gave up on Auto Layout for this reason.

Xcode 5 is not nearly as rude. It allows you to have incomplete layouts while you’re editing the storyboard but it also points out what you still need to fix. Using Interface Builder to create Auto Layout-driven user interfaces has become a lot more fun — and a lot less time-consuming — with Xcode 5.

If you don’t supply any constraints at all, Xcode automatically assigns a set of default constraints, known as the automatic constraints. It does this at compile time when your app is built, not at design time. Auto Layout in Xcode 5 works hard to stay out of your way while you’re designing your user interfaces, and that’s just how we like it.

The automatic constraints give your views a fixed size and position. In other words, the view always has the same coordinates as you see in the storyboard. This is very handy because it means you can largely ignore Auto Layout. You simply don’t add constraints if the default ones are sufficient and only create constraints for those views that need special rules.

OK, let’s play around a bit with constraints and see what they can do. Right now, the button is in the top-left corner and has no constraints. Make sure the button is aligned with the two corner guides.

Add two new constraints to the button using the EditorPin menu, so that it looks like this:

Constraints for the button in the top-left corner

If you hadn’t guessed already, that is the Leading Space to Superview and the Top Space to Superviewoptions.

All the constraints are also listed in the Document Outline pane on the left-hand side of the Interface Builder window:

Button constraints in document outline

There are currently two constraints, a Horizontal Space between the button and the left edge of the main view, and a Vertical Space between the button and the top edge of the main view. The relationship that is expressed by these constraints is:

“The button always sits at 20 points from the top-left corner in its superview.”

Note: These aren’t actually very useful constraints to make because they’re the same as the automatic ones. If you always want your button to be relative to the top-left corner of its superview, then you might as well not provide any constraints at all and let Xcode make them for you.

Now pick up the button and place it in the scene’s top-right corner, again against the blue guides:

Button moved to top-right corner

Whoa, what has happened here? In Xcode 4 this would have broken the old constraints and assigned new ones based on the blue guides, but in Xcode 5 the button keeps the existing constraints. The problem here is that the size and position of the button in Interface Builder no longer correspond with the size and position that Auto Layout expects based on the constraints. This is called a misplaced view.

Run the app. The button will still appear in the top-left corner of the screen:

Button is still in the top-left corner at runtime

When it comes to Auto Layout, orange is bad. Interface Builder drew two orange boxes: one with a dashed border and one with a solid border. The dashed box displays the view’s frame according to Auto Layout. The solid orange box is the view’s frame according to how you placed it in the scene. These two should match up, but here they don’t.

How you fix this depends on what you want to achieve:

  • Do you want the button to be attached to the left edge of the screen at a distance of 254 points? In that case you need to make the existing Horizontal Space constraint 234 points bigger. That’s what the orange badge with “+234″ means.
  • Do you want the button to be attached to the right edge of the screen instead? Then you need to remove the existing constraint and create a new one.

Delete the Horizontal Space constraint. First select it in the canvas or in the Document Outline, and then press the Delete key on your keyboard.

Button with only vertical space constraint

Notice that this turns the Vertical Space constraint orange. Until now it was blue. There is nothing wrong with that particular constraint; it just means there are not enough constraints left to determine the complete position of the button. You still need to add a constraint for the X-position.

Note: You may be wondering why Xcode does not add an automatic constraint for the X-position. The rule is that Xcode only creates automatic constraints if you did not set any constraints of your own. As soon as you add a single constraint, you tell Xcode that you’re now taking responsibility for this view. Xcode will no longer make any automatic constraints and expects you to add any other constraints this view needs.

Select the button and choose EditorPinTrailing Space to Superview. This puts a new constraint between the right edge of the button and the right edge of the screen. This expresses the relationship:

“The button always sits at 20 points from the top-right corner in its superview.”

Run the app and rotate to landscape. Notice how the button keeps the same distance from the right screen edge:

The button in landscape

When you place a button (or any other view) against the guides and make a constraint, you get a spacing constraint with a standard size that is defined by the “HIG”, Apple’s iOS Human Interface Guidelines document. For margins around the edges, the standard size is a space of 20 points.

Now drag the button over to the left a little:

Misplaced button

Again you get a dashed orange box because the view is misplaced. Let’s say this new button position is indeed what you want. It’s not uncommon to make a constraint and then nudge the view by a few pixels, making the orange boxes appear. One way to fix this is to remove the constraint and make a new one, but there is an easier solution.

The Editor menu has a Resolve Auto Layout Issues submenu. From that menu, choose Update Constraints. In my case, this tells Interface Builder it should make the constraint 64 points larger, as so:

Misplaced button fixed

Great, the T-bars turn blue again and the layout is valid. In the Document Outline, you can see that the Horizontal Space constraint no longer has a standard space:

Larger horizontal space in document outline

So far you’ve played with Horizontal Space and Vertical Space constraints. There is also a “center” constraint. Drag a new Button object to the bottom center of the canvas, so that it snaps into place with the guides:

Drag button to bottom center

To keep the button always center-aligned with its superview, on the horizontal axis, you need to add a Center X Alignment constraint. From the Editor menu choose AlignHorizontal Center in Container. This adds a long orange line:

Center X alignment constraint

The line is orange because you’ve only specified what happens to the X-coordinate of the button, not its Y-coordinate. Use the EditorPin menu to add a Vertical Space constraint between the button and the bottom of the view. It should look like this:

Enough constraints for the button

In case you didn’t know how, it is the Bottom Space to Superview option. The Vertical Space constraint keeps the button away from the bottom of the view (again, using the standard margin).

Run the app and rotate it to landscape. Even in landscape mode, the button stays at the bottom center of the screen:

Button stays at bottom center in landscape

That’s how you express intent: “This button should always be at bottom center.” Notice that nowhere did you have to tell Interface Builder what the button’s coordinates are, only where you want it anchored in the view.

With Auto Layout, you’re no longer supposed to care about the exact coordinates of where you place your views on the canvas or what their size is. Instead, Auto Layout derives these two things from the constraints that you set.

You can see this paradigm shift in the Size inspector for the button, which is now quite different:

Different size inspectors

With Auto Layout disabled, typing into the X, Y, Width or Height fields will change the position and size of the selected view. With Auto Layout enabled you can still type new values into these fields, but if you already have constraints set on the view it may now become misplaced. You also have to update the constraints to make them match the new values.

For example, change the Width value of the button to 100. The canvas turns into something like this:

After changing the button width

Xcode 4 would have replaced the Center X Alignment constraint with a Horizontal Space and a new constraint on the button itself that forces it to have a width of 100 points. However, Xcode 5 simply says, “It’s fine with me if you want the width to be 100 points but just so you know, that’s not what the constraints say.”

In this case you do want the button to be 100 points wide. There is a special type of constraint for this: the Fixed Width constraint. First press Undo so that the button is centered again and the T-bars are all blue. Select the button and choose EditorPinWidth. This puts a new T-bar below the button:

Fixed width constraint on button

Select that T-bar and in the Attributes inspector change Constant to 100. This forces the button to always be 100 points wide, no matter how large or small its title. To see this a bit better you can give the button a background color:

Larger width on button

You can also see this new Width constraint in the Document Outline on the left:

Width constraint in document outline

Unlike the other constraints, which are between the button and its superview, the Width constraint only applies to the button itself. You can think of this as a constraint between the button and… the button.

You may wonder why the button did not have a Width constraint before. How did Auto Layout know how wide to make the button without it?

Here’s the thing: the button itself knows how wide it must be. It calculates this based on its title text plus some padding. If you set a background image on the button, it also takes that into account.

This is known as the intrinsic content size. Not all controls have this, but many do (UILabel is another example). If a view can calculate its own preferred size, then you do not need to set specific Width or Height constraints on it. You will see more of this later.

I am not fat

To return the button to its optimal size, first remove the Width constraint. Then select the button and choose Size to Fit Content from the Editor menu. This restores the button’s intrinsic content size.

It takes two to tango

Guides do not appear only between a view and its superview, but also between views on the same level of the view hierarchy. To demonstrate this, drag a new button onto the canvas. If you drag this button close to the others, then their guides start to interact.

Put the new button next to the existing one so that it snaps into place:

Snap two buttons

There are quite a few dotted guidelines here. Interface Builder recognizes that these two buttons can align in different ways – at their tops, centers and baselines.

Xcode 4 would have turned one of these snapping guides into a new constraint. But with Xcode 5, if you want to have a constraint between these two buttons, you have to make it yourself. You’ve seen that you can use the EditorPin menu to make a constraint between two views, but there is an easier way too.

Select the new button and Ctrl-drag to the other button, like so:

Ctrl-drag between buttons

When you let go of the mouse button, a popup appears. Choose the first option, Horizontal Spacing.

New constraint popup

This creates a new constraint that looks like this:

Horizontal space between buttons

It is orange, meaning that this button needs at least one other constraint. The size of the button is known — it uses the intrinsic content size — and there is a constraint for the button’s X-position. That leaves only the Y-position without a constraint.

Here the missing constraint is pretty easy to determine but for more complicated designs it may not always be immediately obvious. Fortunately, you don’t have to guess. Xcode has been keeping score and can tell you exactly what is missing.

There is small a red arrow in the Document Outline, next to View Controller Scene. Click that arrow to see a list of all Auto Layout issues:

Auto Layout issues in document outline

Sweet! Let’s add that missing Y-position constraint. Ctrl-drag from the new button downwards:

Ctrl-drag down from button

The popup menu has different options this time. The items in this menu depend on the context — which views are you dragging between — and the direction you moved the mouse. Choose Bottom Space to Bottom Layout.

The new button now has a Vertical Space to the bottom of the screen, but also a Horizontal Space that links it with the other button. Because this space is small (only 8 points), the T-bar may be a bit hard to see, but it is definitely there.

Click on the Horizontal Space (8) constraint in the Document Outline to select it:

Highlighted horizontal space between buttons

When you select a constraint, it lights up the controls it belongs to. This particular constraint sits between the two buttons. What you’ve done here is say:

“The second button always appears on the left of the first one, no matter where the first button is positioned or how big it is.”

Select the button with the yellow background and type something long into its label like “A longer label”. When you’re done, the button resizes to make room for the new text, and the other button shifts out of the way. After all, it is attached to the first button’s left edge, so that is exactly what you intended to happen:

Button with longer label

Just to get a better feel for how this works, play with this some more. Drag another button into the canvas and put it above the yellow one, so that they snap into place vertically (but don’t try to align the left edges of the two buttons):

Snap green button to top of yellow button

Give the new button a background color (green) so you can more easily see its extents.

Because you snapped the two buttons together, there is now a standard space of 8 points between them that is recommended by the HIG. Turn this into a constraint by Ctrl-dragging between the two buttons. Select Vertical Spacing from the popup menu.

Note: The “HIG”, which is short for iOS Human Interface Guidelines, contains Apple’s recommendations for designing good user interfaces. It is mandatory reading for any iOS developer. The HIG explains which UI elements are appropriate to use under which circumstances, and best practices for using them. You can find this document here.

You are not limited to standard spacing between controls, though. Constraints are full-fledged objects, just like views, and therefore have attributes that you can change.

Select the Vertical Space constraint between the two buttons. You can do this in the canvas by clicking the T-bar, although that tends to be a bit finicky. By far the easiest method is to click on the constraint in the Document Outline. Once you have it selected, switch to the Attributes inspector:

Vertical space attributes

Type 40 into the Constant field to change how big the constraint is. Now the two buttons will be further apart, but they are still connected:

Vertical space between buttons is now larger

Run the app and flip to landscape to see the effect:

Larger vertical space in landscape

The buttons certainly keep their vertical arrangement, but not their horizontal one! The reason should be obvious: the green button does not have a constraint for its X-position yet.

Adding a Horizontal Space from the green button to the left edge of the canvas won’t solve this problem. With such a constraint the green button always keeps the same X-coordinate, even in landscape. That doesn’t look very nice, so instead you are going to express the following intention:

“The yellow button will always be horizontally centered, and the green button will align its left edge with the left edge of the yellow button.”

You already have a constraint for the first condition, but not for the second. Interface Builder shows guides for alignment, so you can drag the top button until its left edge snaps with the yellow button:

Snap left edges

If you also dragged the button vertically, the frame of the button and the Vertical Space constraint may no longer agree on the correct distance. You will see an orange badge on the T-bar:

Badge on vertical space

If this happens, simply use the arrow keys to nudge the button into place again until the badge disappears.

Finally, Ctrl-drag between the two buttons and from the popup menu choose Left. This creates an alignment constraint that says: “The left edges of these two views are always aligned”. In other words, the two buttons will always have the exact same X-position. That solves the layout problem and the T-bars turn blue:

Left-align constraint

Run the app and rotate to landscape to verify that it works:

Left-aligned buttons in landscape

Where To Go From Here?

Now that you’ve got your first taste of Auto Layout, how do you like it? It can take a bit of getting used to, but can make your life a lot easier and your apps much more flexible!

Want to learn more? Keep reading for part 2 of this Auto Layout tutorial, where you’ll continue playing with the buttons in Interface Builder to get a better understanding of the possibilities Auto Layout offers — and the problems you may encounter.

And best of all – you will also use Auto Layout to create a realistic layout that you may find in a real app! :]

In the meantime, if you have any questions or comments please join the forum discussion below!

Objective-C Initializer Patterns | Twitter Engineering Blog

Hi guys, another interesting blog instalment from Twitter, on explaining Initializer Patterns.

Initializer patterns are an important part of good Objective-C, but these best practices are often overlooked. It’s the sort of thing that doesn’t cause problems most of the time, but the problems that arise are often difficult to anticipate. By being more rigorous and conforming to some best practices, we can save ourselves a lot of trouble. In this article, we’ll cover initialization topics in-depth, with examples to demonstrate how things can go wrong.

Part 1: Designated and Secondary Initializers
Part 2: Case Studies
Part 3: Designated and Secondary Initializer Cheat Sheet
Part 4: – initWithCoder:, + new, and – awakeFromNib

Part 1: Designated and Secondary Initializers

Designated initializers define how we structure our initializers when subclassing; they are the “canonical initializer” for your class. A designated initializer does not define what initializer you should use when creating an object, like this common example:

1
[[UIView alloc] initWithFrame:CGRectZero];

It’s not necessary to call the designated initializer in the above case, although it won’t do any harm. If you are conforming to best practices, It is valid to call any designated initializer in the superclass chain, and the designated initializer for every class in the hierarchy is guaranteed to be called. For example:

 

1
[[UIView alloc] init];

 

 

is guaranteed to call [NSObject init] and [UIView initWithFrame:], in that order. The order is guaranteed to be reliable regardless of which designated initializer in the superclass chain you call, and will always go from furthest ancestor to furthest descendant.

When subclassing, you have three valid choices: you may choose to reuse your superclass’s designated initializer, to create your own designated initializer, or to not create any initializers (relying on your superclass’s).

If you override your superclass’s designated initializer, your work is done. You can feel safe knowing that this initializer will be called.

If you choose to create a new designated initializer for your subclass, you must do two things. First, create a new initializer, and document it as the new designated initializer in your header file. Second, you must override your superclass’s designated initializer and call the new one. Here’s an example for a UIView subclass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Designated initializer
- (instancetype)initWithFoo:(TwitterFoo *)foo
{
    if (self = [super initWithFrame:CGRectZero]) {
        _foo = foo;
        // initializer logic
    }
    return self;
}
- (instancetype)initWithFrame:(CGRect)rect
{
    return [self initWithFoo:nil];
}

Apple doesn’t mention much about it in the documentation, but all Apple framework classes provide valuable guarantees due to their consistency with these patterns. In the above example, if we did not override our superclass’s designated initializer to call the new one, we would break the guarantee which makes calling any designated initializer in the hierarchy reliable. For example, if we removed our initWithFrame: override,

1
[[TwitterFooView alloc] init];

could not be relied upon to call our designated initializer, initWithFoo:. The initialization would end with initWithFrame:.

Finally, not all initializers are designated initializers. Additional initializers are referred to as convenience or secondary initializers. There is one rule here you’ll want to follow: Always call the designated initializer (or another secondary initializer) on self instead of super.

Example 1:

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
@interface TwitterFooView : UIView
@end
@implementation TwitterFooView
// Designated Initializer
- (instancetype)initWithFoo:(TwitterFoo *)foo
{
    if (self = [super initWithFrame:CGRectZero]) {
        _foo = foo;
        // do the majority of initializing things
    }
    return self;
}
// Super override
- (instancetype)initWithFrame:(CGRect)rect
{
    return [self initWithFoo:nil];
}
// Instance secondary initializer
- (instancetype)initWithBar:(TwitterBar *)bar
{
    if (self = [self initWithFoo:nil]) {
        _bar = bar;
        // bar-specific initializing things
    }
    return self;
}
// Class secondary initializer
+ (instancetype)fooViewWithBaz:(TwitterBaz *)baz
{
    TwitterFooView *fooView = [[TwitterFooView alloc] initWithFoo:nil];
    if (fooView) {
        // baz-specific initialization
}
    return fooView;
}
@end

Again, the key takeaway from this example is that in both – initWithBar: and + fooViewWithBaz:, we call – initWithFoo:, the designated initializer, on self. There’s one more rule to follow to preserve a deterministic designated initializer behavior: When writing initializers, don’t call designated initializers beyond your direct superclass. This can break the order of designated initializer execution. For an example of how this can go wrong, see Part 2, Case 2.

Part 2: Case Studies

Now that we’ve covered the rules and guarantees relating to designated and secondary initializers, let’s prove these assertions using some concrete examples.

Case 1: Designated Initializer Ordering

Based on the code from Example 1, let’s prove the following assertion: Calling any designated initializer in the superclass chain is valid, and designated initializers are guaranteed to be executed in order from furthest ancestor ([NSObject init]) to furthest descendant ([TwitterFooView initWithFoo:]). In the following three diagrams, we’ll show the order of initializer execution when calling each designated initializer in the hierarchy: initWithFoo:, initWithFrame:, and init.

Case 2: Example bug in UIViewController subclass

In the following example, we will analyze what can happen when we violate the following rule: When writing initializers, don’t call designated initializers beyond your immediate superclass. In context, this means we shouldn’t override or call [NSObject init] from a UIViewController subclass.

Let’s say we start with a class TwitterGenericViewController, and incorrectly override [NSObject init]:

1
2
3
4
5
6
7
8
9
10
11
12
13
@interface TwitterGenericViewController : UIViewController
// Incorrect
- (instancetype)init
{
    if (self = [super init]) {
        _textView = [[UITextView alloc] init];
        _textView.delegate = self;
    }
    return self;
}
@end

If we instantiate this object using [[TwitterGenericViewController alloc] init], this will work fine. However, if we use [[TwitterGenericViewController alloc] initWithNibName:nil bundle:nil], which should be perfectly valid, this initializer method will never be called. Let’s look at the order of execution for this failure case:

Things begin to break even further when subclasses are introduced below this incorrect – init implementation. Consider the following subclass to TwitterGenericViewController which correctly overrides initWithNibName:bundle:

1
2
3
4
5
6
7
8
9
10
11
12
@interface TwitterViewController : TwitterGenericViewController
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        _textView = [[UITextView alloc] init];
        _textView.delegate = self;
    }
    return self;
}
@end

Now, we have failure no matter which initializer we choose.

In this case, there is a failure because TwitterGenericViewController’s initializer is never called.

In this case, all initializers are called, but in the wrong order. TwitterViewController will populate _textView and set it’s delegate, and then TwitterGenericViewController (the superclass) will initialize, overriding the _textView configuration. That’s backwards! We always want subclasses to initialize after superclasses, so we can override state properly.

Part 3: Designated and Secondary Initializer Cheat Sheet

When creating an object

Calling any designated initializer in the superclass chain is valid when creating an object. You can rely on all designated initializers being calling in order from furthest ancestor to furthest descendant.

When subclassing
Option 1: Override immediate superclass’s designated initializer

Be sure to call immediate super’s designated initializer first
Only override your immediate superclass’s designated initializer

Option 2: Create a new designated initializer

Be sure to call your immediate superclass’s designated initializer first
Define a new designated initializer
Document new designated initializer as such in your header
Separately, override immediate superclass’s designated initializer and call the new designated initializer on self

Option 3: Don’t create any initializers

It is valid to omit any initializer definition and rely on your superclass’s
In this case, you ‘inherit’ your superclass’s designated initializer as it applies to the last rule in Option 1

Additionally, you may define class or instance secondary initializers

Secondary initializers, must always call self, and either call the designated initializer or another secondary initializer.
Secondary initializers may be class or instance methods (see Example 1)

Part 4: – initWithCoder:, + new, and – awakeFromNib

+ new

The documentation describes the [NSObject new] as “a combination of alloc and init”. There’s nothing wrong with using the method for initialization, since we’ve established that calling any designated initializer in the hierarchy is valid, and all designated initializers will be called in order. However, when contrasted with [[NSObject alloc] init], + new is used less often, and is therefore less familiar. Developers using Xcode’s global search for strings like “MyObject alloc” may perhaps unknowingly overlook uses of [MyObject new].

– initWithCoder:

Reading Apple’s documentation on object initialization when using NSCoding is a helpful first step.

There are two key things to remember when implementing initWithCoder: First, if your superclass conforms to NSCoding, you should call [super initWithCoder:coder] instead of [super (designated initializer)].

There’s a problem with the example provided in the documentation for initWithCoder:, specifically the call to [super (designated initializer)]. If you’re a direct subclass of NSObject, calling [super (designated initializer)] won’t call your [self (designated initializer)]. If you’re not a direct subclass of NSObject, and one of your ancestors implements a new designated initializer, calling [super (designated initializer)] WILL call your [self (designated initializer)]. This means that apple’s suggestion to call super in initWithCoder encourages non-deterministic initialization behavior, and is not consistent with the solid foundations laid by the designated initializer pattern. Therefore, my recommendation is that you should treat initWithCoder: as a secondary initializer, and call [self (designated initializer)], not [super (designated initializer)], if your superclass does not conform to NSCoding.

 awakeFromNib

The documentation for – awakeFromNib is straightforward:

The key point here is that interface builder outlets will not be set while the designated initializer chain is called. awakeFromNib happens afterwards, and IBOutlets will be set at that point.

Documentation

NSCell has four designated initializers for different configurations. This is an interesting exception to the standard single designated initializer pattern, so it’s worth checking out:

Documentation relating to initialization:

__attribute__ directives in Objective-C | Twitter Engineering Blog


learn-64058_640learn-64058_640

I’ve decided to include a great article from the Twitter Engineering Blog on __attribute__ directives.

In this post, we’ll examine what __attribute__ directives are and how they can be used in development. The goal is to establish a value to using __attribute__ directives in any codebase and to provide a starting point with some directives that anyone can start using right away.

  1. What are __attribute__ directives?
  2. When should I use an __attribute__ directive?
  3. Recognizing the dangers of misusing an __attribute__ directive
  4. Core __attribute__ directives
  5. ARC __attribute__ directives
  6. More __attribute__ directives
  7. in, out and inout
  8. __attribute__ directives as a tool
  9. __attribute__ resources

What are __attribute__ directives?

The __attribute__ directive is used to decorate a code declaration in C, C++ and Objective-C programming languages. This gives the declared code additional attributes that would help the compiler incorporate optimizations or elicit useful warnings to the consumer of that code.

Better said, __attribute__ directives provide context. The value of providing context to code cannot be overstated. Developers have provided context by way of explicit declarations and comments since before the advent of the integrated circuit, but the value of providing context that can be evaluated by a compiler gives us a whole new level of control. By explicitly providing the confines of how an API behaves to the compiler, a programmer can gain some tangible benefits. The directives can be used to enforce compliance with how other programmers consume that API. In other cases, __attribute__ directives can help the compiler to optimize – sometimes to large performance gains.

As Matt Thompson cogently put it in a blog post: “Context is king when it comes to compiler optimizations. By providing constraints on how to interpret your code, [you’ll increase] the chance that the generated code is as efficient as possible. Meet your compiler half-way, and you’ll always be rewarded… [It] isn’t just for the compiler either: The next person to see the code will appreciate the extra context, too. So go the extra mile for the benefit of your collaborator, successor, or just 2-years-from-now you.” Which leads nicely into wise words from Sir Paul McCartney, “and in the end, the love you take is equal to the love you make.”

When should I use an __attribute__ directive?
Whenever you have an opportunity to provide additional context to a code declaration (variable, argument, function, method, class, etc), you should. Providing context to code benefits both the compiler and the reader of the API, whether that’s another programmer or yourself at a future point in time.

Now let’s be practical for a moment too. There are dozens of __attribute__ directives and knowing every single one of them for every single compiler on every single architecture is just not a reasonable return on investment. Rather, let’s focus on a core set of commonly useful __attribute__ directives any developer can take advantage of.

Recognizing the dangers of misusing an __attribute__ directive
Just as poorly written comments and documentation can have consequences, providing the wrong __attribute__ can have consequences. In fact, since an __attribute__ affects code compilation, affixing the wrong __attribute__ to code can actually result in a bug that could be incredibly difficult to debug.

Let’s take a look at an example of where an __attribute__ directive can be misused. Let’s suppose I have an enum that I use pretty often and frequently want a string version for it, whether it’s for populating a JSON structure or just for logging. I create a simple function to help me convert that enum into an NSString.

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
// Header declarations
typedef NS_ENUM(char, XPL802_11Protocol) {
    XPL802_11ProtocolA = 'a',
    XPL802_11ProtocolB = 'b',
    XPL802_11ProtocolG = 'g',
    XPL802_11ProtocolN = 'n'
};
FOUNDATION_EXPORT NSString *XPL802_11ProtocolToString(XPL802_11Protocol protocol);
// Implementation
NSString *XPL802_11ProtocolToString(XPL802_11Protocol protocol)
{
    switch(protocol) {
        case XPL802_11ProtocolA:
             return @"802.11a";
        case XPL802_11ProtocolB:
             return @"802.11b";
        case XPL802_11ProtocolG:
             return @"802.11g";
        case XPL802_11ProtocolN:
             return @"802.11n";
        default:
           break;
    }
    return nil;
}

So I have my great little converting function and I end up using it a lot in my code. I notice that my return values are constant NSString references and are always the same based on the protocol that is provided as a parameter to my function. Aha! A prime candidate for a const __attribute__ directive. So I just update my header’s function declaration like so:

1
FOUNDATION_EXPORT NSString*XPL802_11ProtocolToString(XPL802_11Protocol protocol)__attribute__((const));

And voilà! I have just provided context to any consumer of this function such that they know that the return value is completely based on the provided parameter and won’t change over the course of the process’ life. This change would also provide a performance boost, depending on how often the function is called, since the compiler now knows that it doesn’t actually have to re-execute this function if it already has cached the return value.

Now, let’s say one day I notice the enum value is the character of the protocol and I decide to be clever and change my implementation to something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
NSString *XPL802_11ProtocolToString(XPL802_11Protocol protocol)
{
switch(protocol) {
    case XPL802_11ProtocolA:
    case XPL802_11ProtocolB:
    case XPL802_11ProtocolG:
    case XPL802_11ProtocolN:
       return [NSString stringWithFormat:@"802.11%c", protocol];
    default:
       break;
  }
      return nil;
}

Now since I failed to remove the const attribute, I have just introduced a massive bug that could easily crash my app. Why? Well, the key difference is that the return value of my function is no longer a constant reference. When we were returning hard coded strings before, the compiler stored those strings as persistent memory and those NSStrings effectively had a retain count of infinite. Now that we dynamically generate the string based on the protocol’s char value, we are creating a new string every time – and that means memory that changes. The reference returned in one call to the function won’t actually be the same reference as a subsequent identical call. The problem will rear it’s head when the compiler optimizes subsequent calls to that function to just immediately access what the compiler considers the known return value, which would be the reference returned by the original call. Sadly, that reference has likely been deallocated and potentially reallocated by some other memory allocation by now. This will lead to our application crashing on either a bad memory access or an invalid method call on the object that occupies that reference’s memory. The worst of this is that the optimization that would cause this crash will only happen in builds that are highly optimized. Since debug builds often have optimizations turned down, you can run your app in a debugger forever and never reproduce it, making this bug, like most __attribute__ based bugs, very hard to figure out and fix.

This is bug effectively boils down to treating a function that returns transient memory as const. The same goes for functions or methods that take transient memory as a parameter. Easy enough to remember is that any function returning a pointer return value must return a constant reference to use the const __attribute__ directive and absolutely no const function can have a pointer (including an Objective-C object) as a parameter.

Now this example is merely a precaution for using __attribute__ directives and shouldn’t deter you from using them in your code. If you stick to __attribute__ directives you understand and pay attention to how they are used, you’ll be able to steer clear of these bugs and harness the power __attribute__ directives were meant to provide. Just remember, when in doubt, don’t attribute, because providing the wrong context is worse than providing no context.

To point you in the right direction, below is a compiled list of useful attributes that should be more than enough to improve any developer’s tool belt.

Core __attribute__ directives
__attribute__((availability(…))), NS_AVAILABLE and NS_DEPRECATED

Indicate the availability of an API on the platform

NS_AVAILABLE: Apple macro for attributing an API as available in a given OS release. NS_AVAILABLE_IOS(available_os_version)

NS_DEPRECATED: Apple macro for attributing an API as deprecated in a given OS release.

NS_DEPRECATED_IOS(available_os_version,deprecated_os_version)

  • Use NS_AVAILABLE and NS_DEPRECATED macros to hide the complexity of this attribute.
  • Commonly used when deprecating one API and adding a new API as a replacement.
  • When creating a new API for backwards compatibility, immediately attribute the API as deprecated and include a comment on the API that should be used for current OS targets.
  • These directives are tied to the operating system version and cannot be used for framework versioning. For those instances, use __attribute__((deprecated(…)).
1
2
3
4
5
6
7
8
9
FOUNDATION_EXPORT NSString * const MyClassNotification NS_AVAILABLE_IOS(3_0);
FOUNDATION_EXPORT NSString * const MyClassNotificationOldKey NS_DEPRECATED_IOS(3_0, 7_0);
FOUNDATION_EXPORT NSString * const MyClassNotificaitonNewKey NS_AVAILABLE_IOS(7_0);
NS_AVAILABLE_IOS(3_0)
@class MyClass : NSObject
- (void)oldMethod NS_DEPRECATED_IOS(3_0, 6_0);
- (void)newMethod:(out NSError * __autoreleasing *)outError NS_AVAILABLE_IOS(6_0);
@end

__attribute__((deprecated(…))) and __attribute__((unavailable(…)))
Indicates that an API is deprecated/unavailable.

__attribute__((deprecated(optional_message)))
__attribute__((unavailable(optional_message)))

In case you don’t want to use the availability attribute for deprecation.

1
2
3
4
5
- (void)deprecatedMethod __attribute__((deprecated));
- (void)deprecatedMethodWithMessage __attribute__((deprecated("this method was deprecated in MyApp.app version 5.0.2, use newMethod instead"));
- (void)unavailableMethod __attribute__((unavailable));
- (void)unavailableMethodWithMessage __attribute__((unavailable("this method was removed from MyApp.app version 5.3.0, use newMethod instead"));

__attribute__((format(…))) and NS_FORMAT_FUNCTION

Indicates that a function/method contains a format string with format arguments.

__attribute__((format(format_type, format_string_index, first_format_argument_index)))
format_type: one of printf, scant, strftime, strfmon or __NSString__

Reminder: argument indexes when specified in an attribute are 1 based. When it comes to Objective-C methods, remember they are just C functions whose first 2 arguments are the id self argument and the SEL _cmd argument.

  • NS_FORMAT_FUNCTION: macro provided by Apple for __NSString__ type format string
  • Use NS_FORMAT_FUNCTION macro when attributing a method/function with an objective-c string for formatting.
1
2
3
4
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
void MyLog(MyLogLevel lvl, const char *format, ...) __attribute((format(printf, 2, 3)));
// ...
- (void)appendFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4);

__attribute__((sentinel(…))) and NS_REQUIRES_NIL_TERMINATION

Indicates that a function/method requires a nil (NULL) argument, usually used as a delimiter. You can only use this attribute with variadic functions/methods.

__attribute__((sentinel(index))

index: the index offset from the last argument in the variadic list of arguments.

__attribute__((sentinel)) is equivalent to __attribute__((sentinel(0)))

You’ll almost always want to use the NS_REQUIRES_NIL_TERMINATION macro

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Example 1
@interface NSArray
- (instancetype)arrayWithObjects:... NS_REQUIRES_NIL_TERMINATION;
@end
 
// Example 2 - of course you'd never do this...
NSArray *CreateArrayWithObjectsWithLastArgumentIndicatingIfArrayIsMutable(...) __attribute__((sentinel(1)));
 
void foo(id object1, id object2)
{
    NSArray *weirdArray = CreateArrayWithObjectsWithLastArgumentIndicatingIfArrayIsMutable(object1, object2, nil, YES);
    NSAssert([weirdArrayrespondsToSelector:@selector(addObject:)]);
    // ...
}

__attribute__((const)) and __attribute__((pure))
__attribute__((const)) is used to indicate that the function/method results are entirely dependent on the provided arguments and the function/method does not mutate state.
__attribute__((pure)) is almost the same as its const counterpart, except that the function/method can also take global/static variables into account.

  • Though adding the const or pure attribute to an Objective-C method is not as useful to the compiler due to the dynamic runtime, it is still VERY useful to a programmer reading an interface.
  • It is recommended that all singleton instance accessors use the const attribute.
  • The optimization upside of accurately using this attribute can be an enormous win. If you have an Objective-C class method that is frequently used and is const or pure, consider converting it into a C function to reap some serious benefits.
  • On the flipside, using this attribute incorrectly can lead to a nearly impossible to locate bug as actually seeing the redundant use of the function removed by the compiler requires looking at the assembly! Oh, and this type of bug will rarely show in a debug build since only highly optimized builds will have the bug.
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
// Example 1: Singleton
@interface MySingleton : NSObject
+ (MySingleton *)sharedInstance __attribute__((const));
@end
// Example 2: Function overhead optimization
// Get the description of a specified error number
const char *StringForErrNo(int errorNumber) __attribute__((const));// strerror(errorNumber)
// Get the description of the global errno error number
const char *StringForGlobalErrNo(void) __attribute__((pure)); // strerror(errno)
void DoStuffWithGlobalErrNo()
{
      NSLog(@"%@ %s", [NSStringstringWithUTF8String:StringForGlobalErrNo()],StringForGlobalErrNo());
      printf("%sn", StringForGlobalErrNo());
      printf("%in"strlen(StringForGlobalErrNo()));
}
// will compile as something more like this:
void DoStuffWithGlobalErrNo()
{
const char *__error = StringForGlobalErrNo();
NSLog(@"%@ %s", [NSString stringWithUTF8String:__error], __error);
     printf("%sn", __error);
     printf("%in"strlen(__error));
}
// which effectively eliminates both 1) the overhead of the function call and 2) the internal execution cost of the function
// Example 3: Function execution cost optimization
int nthFibonacci(int n) __attribute__((const)); // naive implementation to get the nth fibonacci number without any caching
void TestFibonacci()
{
     time_t start = time(NULL);
     int result1 = nthFibonacci(1000); // execution time of D
     time_t dur1 = time(NULL) - start; // some large duration D
     int result2 = nthFibonacci(1000); // execution time of 1
     time_t dur2 = time(NULL) - start; // same as dur1, duration D
     int result3 = nthFibonacci(999); // execution time of ~D
     time_t dur3 = time(NULL) - start; // duration of 2*D
// The __attribute__((const)) directive can effectively eliminate a redundant call to an expensive operation...nice!
}

 

__attribute__((objc_requires_super)) and NS_REQUIRES_SUPER
Indicate that the decorated method must call the super version of it’s implementation if overridden.

  • Existed in LLVM for Xcode 4.5 but had bugs and wasn’t exposed with NS_REQUIRES_SUPER until Xcode 5.0
  • When creating a class that is expressly purposed to be a base class that is subclassed, any method that is supposed to be overridden but needs to have the super implementation called needs to use this macro.
  • This attribute can be a large codebase win by contextualizing what methods are necessary for a base class to work. Widely adopt this attribute and your codebase will benefit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@interface MyBaseClass : NSObject
- (void)handleStateTransition NS_REQUIRES_SUPER;
@end
// ...
@interface MyConcreteClass : MyBaseClass
@end
@implementation MyConcreteClass
- (void)handleStateTransition
{
     [super handleStateTransition]; // <-- without this line the compiler will generate a warning (great for catching bugs!)
     // do more stuff
}
@end

 

ARC __attribute__ directives
__attribute__((objc_precise_lifetime)) and NS_VALID_UNTIL_END_OF_SCOPE

Indicate that the given variable should be considered valid for the duration of its scope

  • Though this will rarely come up, it can be a big help combatting a brain scratching crash that only appears in release builds (since the optimization likely doesn’t happen in your debug build)
1
2
3
4
5
6
7
8
9
10
11
12
- (void)foo
{
    NS_VALID_UNTIL_END_OF_SCOPE MyObject *obj = [[MyObject alloc] init];
    NSValue *value = [NSValue valueWithPointer:obj];
// do stuff
    MyObject *objAgain = [value pointerValue];
    NSLog(@"%@", objAgain);
}
/* in ARC, without NS_VALID_UNTIL_END_OF_SCOPE, the compiler will optimize and after the obj pointer is used to create the NSValue the compiler will have no knowledge of the encapsulated use of the object in the NSValue. ARC will release obj and this NSLog line will crash with EXEC_BAD_ACCESS because the reference retrieved from the NSValue and stored in objAgain will now be pointing to the deallocated reference. */

__attribute__((ns_returns_retained)) and NS_RETURNS_RETAINED
Indicates to ARC that the method returns a +1 retain count.
Per Apple: only use this attribute for extraneous circumstances. Use the Objective-C naming convention of prefixing your method with alloc, new, copy, or mutableCopy to achieve the same result without an attribute.

  • ARC will follow a naming convention and this directive for how to manage the returned value’s retain count. If the implementation is non-ARC, it is up to the implementation to adhere to the rule such that when an ARC file consumes the API the contract is adhered to.
  • Honestly, you should just use the Apple recommend method prefix for methods and reserve this only for cases where you create an object with a +1 retain count with a function.
1
NSString *CreateNewStringWithFormat(NSString *format, ...)NS_FORMAT_FUNCTION(1, 2) NS_RETURNS_RETAINED;

__attribute__((ns_returns_not_retained)) and NS_RETURNS_NOT_RETAINED

Indicates to ARC that the method returns a +0 retain count. Default behavior of all methods and functions in Objective-C.
Per Apple: only use this attribute for extraneous circumstances. Use the Objective-C naming convention of NOT prefixing your method with alloc, new, copy, or mutableCopy to achieve the same result without an attribute.

  • ARC will follow a naming convention and this directive for how to manage the returned value’s retain count. If the implementation is non-ARC, it is up to the implementation to adhere to the rule such that when an ARC file consumes the API the contract is adhered to.
  • The only use for this attribute would be if you prefixed a method with alloc, new, copy, or mutableCopy but you didn’t want a +1 retain count – which is just nonsense. You should never need to use this attribute as it is implied on any method that doesn’t have a +1 keyword prefix.
1
- (NSString *)newUnretainedStringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4) NS_RETURNS_NOT_RETAINED;

 

__attribute__((objc_returns_inner_pointer)) and NS_RETURNS_INNER_POINTER
Indicates that the method will return a pointer that is only valid for the lifetime of the owner. This will prevent ARC from preemptively releasing an object when the internal pointer is still in use.

  • This is actually a very important attribute that few developers do a very good job of using, but really should. If a method returns a non Objective-C reference, then ARC doesn’t know that the returned value is a reference that belongs to the owning object and will go away if the owning object goes away. Without this attribute, after the final use of an object ARC will release it. This can result in a crash if the inner pointer is referenced after the last use of the object since it could have been deallocated. Ordering lines of code is not enough either, since the compiler could easily reorder the execution order as a way to optimize.
1
2
3
4
5
6
7
8
9
10
11
12
13
@interface NSMutableData : NSData
- (void *)mutableBytes NS_RETURNS_INNER_POINTER;
@end
void Foo(void)
{
     NSMutableData *buffer = [[NSMutableData alloc] initWithLength:8];
     char* cBuffer = buffer.mutableBytes;
     memcpy(cBuffer, "1234567", 8); // crash if NS_RETURNS_INNER_POINTER doesn't decorate the mutableBytes method
     printf("%sn", cBuffer);
     (void)buffer; // this will not save us from a crash if the mutableBytes method isn't decorated with an NS_RETURNS_INNER_POINTER
}

 

__attribute__((ns_consumes_self)) and NS_REPLACES_RECEIVER
Indicates that the provided method can replace the receiver with a different object.
Presumes a +0 retain count (which can be overridden with NS_RETURNS_RETAINED, but if you do that you really need to be asking yourself “what the heck am I doing?”).

  • By default, all methods prefixed with init are treated as if this attribute were decorating them.
  • ARC makes this behavior really easy to implement. non-ARC implementers of the same behavior still need the decoration but also have to pay closer attention to how they are managing memory in the implementation. (awakeAfterUsingCoder: is regular source of memory leaks in non-ARC code bases)
1
2
3
@interface NSObject (NSCoderMethods)
- (id)awakeAfterUsingCoder:(NSCoder *) NS_REPLACES_RECEIVER;
@end

 

__attribute__((objc_arc_weak_reference_unavailable)) and NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE
Indicates that the decorated class does not support weak referencing

  • Mac OS X Examples: NSATSTypesetter, NSColorSpace, NSFont, NSMenuView, NSParagraphStyle, NSSimpleHorizontalTypesetter, NSTextView,NSFontManager, NSFontPanel, NSImage, NSTableCellView, NSViewController, NSWindow, and NSWindowController.
  • iOS and Mac OS X Examples: NSHashTable, NSMapTable, or NSPointerArray
1
2
3
4
NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE
@interface NSHashTable : NSObject </*Protocols*/>
//...
@end

 

NS_AUTOMATED_REFCOUNT_UNAVAILABLE
Indicates that the decorated API is unavailable in ARC.

  • Can also use OBJC_ARC_UNAVAILABLE
1
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;

More __attribute__ directives
__attribute__((objc_root_class)) and NS_ROOT_CLASS
__attribute__((constructor(…))) and __attribute__((destructor(…)))
__attribute__((format_arg(…))) and NS_FORMAT_ARGUMENT
__attribute__((nonnull(…)))
__attribute__((returns_nonnull))
__attribute__((noreturn))
__attribute__((used))
__attribute__((unused))
__attribute__((warn_unused_result))
__attribute__((error(…))) and __attribute__((warning(…)))

in, out and inout

While we’re on the topic of providing context to code we should take the briefest of moments to bring up the Objective-C keywords in, out and inout. These little keywords are used to attribute Objective-C method arguments to provide context on whether the parameter is for input, output or both. These keywords came about with distributed objects along with oneway, byref, and bycopy but, in the spirit of providing context to programmers, these keywords can bridge the gap between the consumer of an API presuming how an argument will behave and knowing how that argument will behave. Consider using inout or out the next time you return a value via an argument and consumers of your API will appreciate it.

in
Indicates that the given argument is used only for input. This is the default behavior for non-pointers and Objective-C objects.

  • Use this keyword for methods that accept a pointer to a primitive that is read but never modified. Not a common case.
1
2
3
4
5
6
7
- (void)configureWithRect:(in CGRect *rect)
{
    if (rect) {
        _configRect = *rect;
    }
    [self _innerConfigure];
}

out
Indicates that the given argument is used just for output. This is never a default behavior.

  • This keyword doesn’t make sense to apply to non pointers, which are always in arguments.
  • Use this keyword for methods that return a value via an argument but don’t read that argument.
1
2
3
4
5
6
7
- (void)configure:(out NSError **error)
{
     NSError *theError = [self _configure];
     if (error) {
        *error = theError;
     }
}

 

inout
Indicates that the given argument is used for both input and output. This is the default behavior for pointers, except for Objective-C objects (which default to in).

  • This keyword doesn’t make sense to be applied to non pointers, which are always in arguments.
  • Use this to provide context when it may not be apparent how the pointer behaves.
  • Always use this to provide context when a method has numerous pointer arguments and at least one is in or out. Basically, when there are multiple pointer arguments and they are not all inout, every pointer argument should specify its behavior.
1
2
3
4
5
6
7
8
- (void)configureRect:(inout CGRect *rect)
{
     if (rect) {
         if (CGRectIsNull(*rect)) { // where rect acts an "in" argument
             *rect = CGRectMake(_x, _y, _w, _h); // where rect acts as an "out" argument
          }
      }
}

 

__attribute__ directives as a tool
With such a valuable tool available to the C languages, any team can benefit by using these __attribute__ directives to give context in their code. At Twitter, with a very large code base and many engineers developing on it daily, every bit of context that can be provided helps in maintaining a quality code base for reuse. Adding __attribute__ directives to your toolbelt of code comments and good naming conventions will give you a robust toolset for providing indispensable context to your code base. Don’t shy away from adding __attribute__ directives to your next project. Use them, evangelize them and everyone will benefit.

__attribute__ resources
GCC __attribute__ documentation
Clang __attribute__ reference
Clang Objective-C ARC Attributes
NSHipster’s __attribute__ blog post