Rapture In Venice, LLC – John Blanco

:: Freelance iOS and Xamarin Development

Too Many Images Slowing Down Interface Builder

The Problem

On a project I’m working on, I’d noticed that Interface Builder started running really slowly once I’d added something on the order of 2,000 PNG’s to my XCode project. Why would I add so many images you ask? Because I needed to. :-) So, the result was that opening up any XIB file caused a 5-10 second beach ballin’ before it would allow me to do any modifications to the XIB.

The problem was certainly annoying, but the other developer and I grinned and beared it because it wasn’t horrific enough to do anything about and we didn’t know there was something we could do about it.

Fast forward a couple months later and we were required to multiply the project by four. The client wants to release four versions of the app, all with their own sets of icons. By this time, I should mention, the icons had grown to 5,000 and so that meant the app would now have over 20,000 PNG files!

Suffice to say, Interface Builder became completely non-responsive, locking up far too long for even the Mac to handle. Something had to be done.

The Solution

XCode has a feature that allows you to provide your own custom scripts to run during the build process. Most of us have heard about this but have never used it for lack of a sufficient reason. Wel, I’d gotten my reason!

What I did was remove all the PNG’s from the project (actually, remove the references from XCode) and move them into a set of named directories that represented each target. Next, I added a script to the build. Here’s what you do:

1. Right-click on the target and select Add -> New Build Phase -> New Run Script Build Phase.

2. Specify the commands to copy the files into the bundle.

Copy the image files into the bundle

Copy the image files into the bundle

XCode supports plenty of build variables. In fact, everything in your build target’s Build tab is supported. Be sure to right-click in there and select Show Setting Names to get the real names. In the case above, SRCROOT is the same directory as your XCode project file (and where most of your files reside), TARGET_BUILD_DIR is where your app is being built and PRODUCT_NAME is used to resolve to the actual .app file. (I was unable to find a build config that gave me the whole thing)

Another useful config which I’ve not seen documented much anywhere is CONFIGURATION. I literally guessed at it. It will return Debug, Release, Distribution or whatever the name of your build target is. Very handy if you want to do something like this:

if [ "${CONFIGURATION}" != "Debug" ]; then /bin/cp -R ${SRCROOT}/TargetA-Resources/ ${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app ; fi

In this case, I avoid copying the PNG’s when doing a Debug build. The reason is that the icons are not necessary for the program to operate and it saves me time when loading the app on the phone every time. Use it as you need it.

It’s also important to note a nuance here. The cp -pR command will copy the contents of a directory if it is specified with a trailing /. If not, it copies and maintains the directory and its contents. In this case, since bundle resources go in the top-level of the directory, I just copied the contents of the directory by specifying the trailing /.

Also note that I didn’t specify *.png. When I did specify it, I got an error that the command line was too big. Likely, it was expanding *.png into the full list of files which, as we know, is huge. So, you may need to similarly adjust the command to capture what you need in a shorter space. Like in my case, you can do this by putting all your files in a directory and copying them with cp -R.

3. Close the window, name the new build phase, and position it appropriately.

Position the build phase either right before or right after the other resources are bundled

Position the build phase either right before or right after the other resources are bundled

I chose to place them right after the other bundled resources are included just to keep them close and it “felt” right, but doing it beforehand should work just as well.

Build, run, and done! You should find your build is a LOT faster and Interface Builder goes back to being super-speedy. Hooray!

NOTE: You may want to use pngcrush to crush the PNG’s either via the command-line or, as I prefer, beforehand so you don’t have to do it over and over. Your decision should depend on how often the PNG’s change. In our case, they hardly ever do.

  • Print
  • Facebook
  • Twitter

John Blanco

John Blanco is a freelance iOS and Xamarin developer living in Lakewood, CO. He's been developing mobile apps for 10 years, beginning in the medieval days of Java ME and Blackberry, making him the ultimate hipster mobile engineer. Follow him on Twitter!

More Posts

Follow Me:


Comments are currently closed.