Pro Tip: Playback Speed

Videos are a great way to consume information but they can sometimes drag their feet when it comes to getting to the important subject matter. When reading a blog or a book you can just skim read over the things you already know but this is difficult with video. I generally watch most programming podcasts/tutorials or conference talks at 2x and then just slow down when I need to take more time to digest the content.

Native video

I use iTunes to subscribe to a few great podcasts like RubyTapas, NSScreencasts etc. The content is often great but the podcasts are aimed at a broad audience and so some things I can happily skim over. I don't know if there is a better podcast player I should be looking at but I generally just open the podcast in QuickTime which allows my 2x playback.

Youtube

There is too much great content to call out but Confreaks is one of my favorite channels for interesting talks. To get 2x playback speed on Youtube you need to ensure that you are using the HTML player.


The other obvious benefit to watching things at 2x speed is that they take half the time to watch. This is awesome especially if you are following series like Handmade Hero where the videos can easily be between 1-2 hours. It may not be possible to watch a whole video at 2x when it is dense with information but at least you can budget your time more wisely by skimming the less important details.

ximber

I've created a simple tool called ximber that hopefully helps with making xibs just a little bit nicer to work with.


The why

A painful problem when working with layout constraints in xibs and storyboards is that they are almost impossible to revisit at a later date and make quick changes on. The problem stems from the fact that the constraints you make have terrible names and there can be a large amount of them even for relatively simple interfaces. It is often easier to remove all constraints and start again if it's been a long time since you set an interface up. This is because clicking between the constraints and then building up a mental stack of what each does is just plain exhausting.


The first step (manual)

Some people know that you can help yourself out by adding labels* to each constraint to give yourself a prompt about what the constraint does. This could be as simple as using VFL to state that a constraint is for setting a view called myView's height to 100 (V:[myView(==100)]). This is exactly what I started doing and I found that it was a great help, constraints were much easier to find and work with in interface builder, especially in a team environment where you may not have set the constraint up. A pretty major flaw in this approach is that you are essentially adding a comment to the xib and as we all know comments will try their hardest to stay out of sync with actual code.


The next step (automate)

The aim of ximber is to automate this process. The idea is simple

  • Parse the xib's XML
  • Grab any constraints
  • Try to generate a meaningful label for each constraint (this is slightly awkward)
  • Write the xib back out

More problems

Believe it or not generating a label like this: H:[view]-[view][view]-[view] is not very useful. This will happen if you have poorly named views:

poor naming

What would be really good is if each view had a decent name as well. A simple idea would be to just manually add a label to each view, which you could argue is just good house keeping. ximber aims to help with some of the leg work by giving views in your xibs a reasonable name. Obviously it's not just going to guess what to call things - so what it does is examine the IBOutlet connections that are connected to your outlets. If a view is connected up then it will add a user label with the name of the property. ximber will only add a user label if there isn't one already so it won't clobber any manually added labels.

With nicely named view outlets and constraints you end up with the following:

Before

Image Alt

After

Image Alt


Before

Image Alt

After

Image Alt


This is a personal tool and as such I've not considered any decent way of making it easy to install :/ If you grab the project from the repo you can build and put the product somewhere in your path.

This was a weekend project and as such may not be the fully finished article - any feedback, pull requests or bugs would be greatly appreciated.


* Adding labels is as simple as

  • Select an outlet
  • Hit return

OR

  • Select an outlet
  • Wait a short delay
  • Select the outlet again

OR

  • Select an outlet
  • Go to the identify inspector
  • Edit the label in the Document section

What did I just compile?

In most projects you'll reach a point where you want to run slightly different code depending on the type of build configuration you are using. You may want to only use logging in DEBUG or potentially use different API keys for services between ad hocs and store builds. The process of doing this is fairly straight forward and uninteresting but I'm just going to point out how the pieces fit together and a couple of ways to test your setup to give you the confidence that the correct code will go to the app store and you don't end up with egg on your face.

Let's say we want to remove all occurrences of NSLog() in our project for any build configuration that is not DEBUG - simple enough.

Prefix.pch

#ifndef DEBUG
#  undef  NSLog
#  define NSLog(...)
#endif

#ifndef?

So the first line #ifndef DEBUG is a compiler directive to check to ensure that the token DEBUG has not been defined in this file or any included files. If DEBUG has been defined then it removes the next two lines before compilation. If DEBUG has not been defined then these lines will be compiled and have the effect of replacing all calls to NSLog() with nothing. If we want to check that a token has been defined we use the similar looking #ifdef.

So hopefully the above was nothing new or interesting but you may be wondering where and why would DEBUG be defined as I don't do it manually?


Where's my define?

This is where the Xcode templates help us out a little. Jump to the build settings of a project and search for 'preprocessor macros' and you'll see something like this:

Preprocessor Macros

As you can see from the above screenshot the Xcode default project settings have the define DEBUG=1 declared but only for the debug configuration.

There is nothing special about how this is done that prevents you from adding your own defines. For example you may want to augment this so you can check other configurations. In the screenshot below I add RELEASE=1 for release builds and ADHOC=1 for a new configuration made for ad hocs.

Preprocessor Macros


Location, location, location

So were would you put some code to remove NSLog()? It needs to be available everywhere to ensure that it effects every NSLog. A common place could be to just slap it in the {Project}-Prefix.pch file. This file will have been automatically created for you when starting with one of the Xcode templates.

I used the term "just slap it in the {Project}-Prefix.pch" as this is the simplest way to get code included everywhere in your project, but it's not pretty. If you have too much code that you want to use everywhere your .pch will start to look like a dumping ground and it's probably time to move this stuff into a better named file and include that in the .pch. Yes I know this is just hiding the code in another file but it certainly seems like a good compromise of convenience and tidiness, the alternative being to #import your new file everywhere you want to use your new code.

Slight detour

If you want to rename the .pch you have to also ensure that you update the build settings to reference the new name. The quickest way to find the setting is to use the filter on the build settings tab of the project and look for "prefix header":

Image


Rocky waters

The .pch suffix actually stands for pre compiled header and it's precompiled to speed up your build times. This means that Xcode can get a little bit moody if anything changes in any of the imported files - for that reason it's best to only #import stable things (things that don't change often) into the .pch. If you get into a situation where your project builds but Xcode spits out warnings related to the files that are #import'd into your .pch you have to do a little dance to get Xcode working again.

I generally follow these steps - I build at each point and if the warnings go away you are done, if not keep going through the list

  1. Do a full clean (⌘⌥⇧K)
  2. Comment out the offending import, build, then uncomment the import, build
  3. Do step 1 again and also delete derived data
  4. Close Xcode
  5. If you got here you are having a bad day :(

Test

Great so you are using different build configurations to remove or add code but how do you get the confidence to know that you are not about to release the wrong code to the app store?

Ad hoc

You should definitely without fail make an ad hoc using the configuration that you will use when going to store. To do this go to Product > Scheme > Edit Scheme (⌘<), switch to Archive and ensure that the Build Configuration is set to your app store configuration (most likely Release).

Release config

Now just test your app and make sure that it behaves as you expected.

Preprocess

If you are like me and want to go full belts and braces you'll want to see the code that will be run (seeing is believing). To do this edit the Run settings go to Product > Scheme > Edit Scheme (⌘<), switch to Run and ensure that the Build Configuration is set to your app store configuration (most likely Release).

Run config

Now with the file that contains the conditional open go to Product > Perform Action > Preprocess "MyFile.m"

Preprocess

Xcode will make itself busy and then spit out the preprocessed file, which you can now search to ensure that the correct code was included/excluded. ProTip: your code will be way way way down the file, right near the bottom.

Wrap up

I'm not going to lie this was not a very interesting post but it's important to know how this stuff works to make sure that you are not accidentally including bad code in production builds.

Believe it or not there was a couple of useful/interesting things in the above post:

  • Looked at 2 build settings Preprocessor Macros and Prefix Header
  • Learn the Xcode dance when the .pch gets itself in knots
  • Test your code to be confident that the #ifdef's are working as advertised

I think the ways of testing are the most important take away as it's never a good idea to trust the code you just copied and pasted from StackOverflow. Your project may be configured differently and it would be foolish to trust a computer to "just work".