IPA Targets for iPhone — Why and How?
Admittedly, one of the most annoying parts of building iPhone apps for clients is merely giving them the app to install. The usual case is that you hand them a *.app directory that, to a Mac user, looks like a file, but to a client using Windows it’s a directory. And when Windows users open this directory, files tend to be added by Windows Explorer. This wouldn’t be so bad except that the content changes rewrite the hash signature and users then have trouble installing your iPhone Ad Hoc builds.
It’s gotten so bad that the first thing I tell clients when they have trouble is to “re-download the build and DO NOT OPEN THE FOLDER.” 9 times out of 10 this fixes the problem, but it doesn’t have to be this way.
What is an IPA?
Enter IPA’s. The best that I can tell, an IPA is just Apple’s internal way of bundling apps together. Luckily, we can do it, too! What is an IPA? It’s a file. YES. A file. A real one. What this means is that your clients (and heck, even some of your fellow developers!) can’t mess it up. :-)
Setting Up an IPA Build Target
Simple! All you need to do is set up a new build target. I call mine IPA, but you can call it whatever you want. Here’s the process:
- Create a new build target, of type “Other/Aggregate” (see the Mac OS X section)
- Add the build targets you want to build IPA’s for as direct dependents. This means they will get built before the IPA target is built.
- Add a new Run Script Build Phase to the IPA target.
- Now cut and paste the following code:
APPS="MyAppName" cd $CONFIGURATION_BUILD_DIR for i in $APPS do echo Creating IPA for $i.app mkdir -p Payload cp -R $i.app Payload cp $SRCROOT/Resources/itunes-icon.png $CONFIGURATION_BUILD_DIR/iTunesArtwork zip -qr $i.ipa Payload iTunesArtwork rm -rf Payload rm iTunesArtwork done
The only things you need to change in the above is MyAppName and whatever your iTunes artwork is called (the 512×512 version). The artwork isn’t vital, but it appears in your iTunes library when you install and it’s ugly not to see an icon.
Replace MyAppName with whatever your *.app name is. The best way to figure this out is to double click your app’s regular target, click the Build Tab, and find the value for “Product Name”.
Now, to build the IPA just set your Active Target to IPA, use whatever build configuration you want, and you’re good to go!
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.
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.
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.
A UITabBarController Without Binding Items to Views
I’ve run across this on a project where I wanted what amounts to a UITabBarController for my iPhone app, but I want to have ONE shared view for 4 of the 5 tabs. This is impossible with UITabBarController as far as I can tell.
However, there is hope. With a slightly different implementation, you can have the Tab Bar in your app without the lockdown on functionality.
First, remove the UITabBarController from your MainWindow.xib or wherever else you have it.
Second, add a UITabBar to the window. This is in the library under “Windows, Views & Bars”. Notice it’s just the component, not the full controller.
Third, customize your items, and add Tab Bar Items as needed.
Fourth, set the delegate of this object to whatever listener you want. I do this programmatically, but you can do it how you like. You just need a class that implements UITabBarDelegate, *not* UITabBarControllerDelegate.
Fifth, implement:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item { // do something based on item }
Sixth, add logic so that based on the item (you can compare by using IBOutlet to get a reference to all the items or look at the labels). In my case, I transformed by single view based on which item was selected.
And presto!
Don’t Mix and Match your Google and Yahoo GPS!
Something interesting came up while working on a project of mine. The client wanted us to build a Store Locator but (A) couldn’t provide a Web service to the same stuff on their Web site and (B) could provide store information but not the GPS coordinates.
I had some options for how to handle this, and one of them was to screen scrape their Web site. However, there’s a lot of risk in that of course and I decided that even though the project was just 8 days to write their iPhone app, I’d do it the right way.
The process of writing a Store Locator are tricky, but if there’s interest I can describe it more fully in a future post. However, for sake of time, I want to focus on just one aspect: a bug with geocoding the addresses.
I used the GPS Visualizer service to run all 450 store locations through and get latitude/longitude for each. I wrote several scripts to automate as much as possible this very manual process. However, after successfully doing it and testing the app it became apparent the stores were not located exactly where I knew they were.
My first concern was that the service was bad. Perhaps it didn’t interpret the addresses well enough? I was a little worried because I knew it might take a lot more time to find another batch processor and carefully validate the results.
But, then I found the problem.
GPS Visualizer, by default, uses the Yahoo! GPS service to do its geocoding. However, the iPhone uses Google Maps! Lo and behold, they are not compatible!! There is a margin of error either in the locations or the mapping, but long story short I changed the source to Google on GPS Visualizer and the data was perfect!
So, take this as a warning. Yahoo! and Google location information are not compatible. In my experience, the Yahoo data was about 5 city blocks off from Google’s.
Somebody is mistaken. I wonder who?
Why I Switched from PureMVC to Mate…
This article is written with the assumption that the reader has at least some familiarity with the Flex MVC frameworks, PureMVC and Mate. However, knowledge of these systems is not required.
I Love You, PureMVC
For about a year now, I have used PureMVC exclusively for my Flex projects. I chose the framework because I could grasp all of the concepts and really understand the vision. Mediators could deliver on separating the views from the rest of the applications. Proxies could deliver models without having Singletons all over. Commands, well, we all know those. Combine it all under the ApplicationFacade, and everything made sense. I was sold.
Until recently…
PureMVC, Uh, I Think It’s Time We See Other Frameworks
In recent months, our relationship has hit the rocks. Over time, I’d completely ceased using Proxies. In earlier projects, I littered all of my code with retrieveProxy() calls. As I gained more experience, I tried to keep those calls within Mediators and Commands only. It took some work, but I learned something: Proxies don’t give me anything. So, I have skipped the unnecessary boilerplate and I just use the Model Locator pattern from Cairngorm, which is much simpler.
Commands still made me happy, but it was bugging me that I was calling sendNotification() from my client code. I tried to eliminate that. I pushed those calls into the Mediators and fired regular Flash events to get them initiated from those Mediators. To accomodate that, I began writing more Mediators. So now, I would add classes like DialogMediator, SoundFXMediator, and so on. Depending on how you architect your applications, you may or may not like this idea. I think they make sense in the context, but I was starting to lose my love for coding due to all the overhead boilerplate needed for each one.
“Well, at least my Mediators are powerful,” I thought. The growing number of them, anyway. Admittedly, I still have an affinity for them. You can perform such a wide range of functionality with them. Fire off a notification and you can have your Mediator enable and disable fields, reposition components, and do just about anything else.
Ummm, well, OK, one problem is that my mediators started having too much logic. It’s just too easy to perform all of my view manipulations in the Mediator, thereby making the View too dumb to reuse somewhere else. For example, if the status of the components had to be managed based on some model state, I found that the code for that would invariably all end up in the Mediator, not the view. If I were to pull the view out of my PureMVC application, I’d have to rewrite all of that code!
So, with me using only two-thirds of the framework, getting frusterated with the boilerplate code, and questioning if I’m putting my code in the right places, I wanted to see if there was something better out there.
Cairngorm? Hell no. Cairngorm is a piece of crap. Quote me on that. Commands…whoopeee dooo!
A retroactive work friend turned me on to Mate (though he hadn’t used it yet), so I took a look at it. I loved it.
This article is about my transition to the Flex Mate MVC framework.
Why I Switched To Mate
What attracted me to Mate were some key differences with PureMVC:
- Less boilerplate would be needed.
- Standard Flash events could be used for communication instead of custom classes like Notification.
- Event Maps offered a facility that replaces a lot of your need to write Commands and simplifies server communications.
I’ll go over some of these concepts in the next few sections. Hopefully, you’ll be as excited about Mate as I am.
Proxies: Migrating to Mate Models
Yeah, this was really easy. I didn’t have to do nothin’ since I wasn’t using Proxies anymore anyway. :-)
Mate doesn’t use any framework-specific classes for Models. So, you’re free to specify your models however you wish: Singleton model, static model, whatever. Models are models with no boilerplate needed and no guilt for not using it. W00t!
Commands: Almost Exactly The Same (If You Still Need Them)
At the very least, you’ll find that Commands are practically the same between PureMVC and Mate. However, it’s the small differences which make Mate Commands such an attractive choice.
First, the Mate Command doesn’t need to extend a class like SimpleCommand. Any class can serve as a command so long as it implements a method with the signature execute(event:Event):void. This offers a few benefits:
- You can test Commands using FlexUnit or DPuint without being forced to use the MVC framework as well.
- Your Command has more flexibility in what you want it to subclass.
- Less boilerplate if you’re writing it by hand.
Another thing you’ll notice is that you really don’t need to write so many Commands anymore. Instead of responding to an event by firing a Command, you actually have the ability to do things like send HTTP requests and invoke methods directly. Now, you might want to write your Command class anyway — and that’s fine — but the option to push more implementation into Event Maps will be there and, especially for smaller apps, you may find yourself doing this quite a lot and it’s a far better way to do things than PureMVC.
Event Maps are a big topic when it comes to replacing Mediators.
Mediators: Everything You Know Is Wrong
There is no question that the hardest thing I had to do to commit to Mate was moving from PureMVC Mediators to Mate’s Injectors. Mediators are incredibly flexible and a big reason why I’m a PureMVC fan. Here’s what they give you:
- An extremely generic way for a view to handle notifications.
- A way to control a set of view components without even having to composite them.
- Separation of UI and Command code when responding to a single notification.
I’ve used Mediators for some of the following tasks:
- Controlling component states.
- Populating controls without binding. (This can be faster in many situations.)
- Non-UI actions such as playing sounds and popping up dialogs.
What can’t they do??
The first you notice with Mate is that it doesn’t have the concept of a Mediator, but they it does have Injectors. While far less broad in what they can do, I do believe Injectors offer a more solid design pattern than the way I’ve been using (or misusing) Mediators.
Injectors can be thought of as data bindings, except they work with ALL views of a type. The Injector always modifies the targetKey for every instance of your view target. This can be good and bad. If you want all your views to react the same to model changes, it’s great. If you think using an Injector on a Label is a good idea, you’re mistaken. If you did this, all of your Labels would change when an injection happens!
However, while this jumped out in my mind as a possible problem, I realized that PureMVC does the same thing. For example, let’s say you have a component that has its own Mediator. Now, if you wanted multiples of that component, you’d create more components and call registerMediator() multiple times for each one. It sounds right, anyway.
There’s a problem, though. In PureMVC, removeMediator() takes a constant, namely that Mediator’s NAME constant. You can’t remove an individual Mediator! In effect, Mediators are singletons, whether you’ve realized it yet or not. You’re only recourse is to subclass the Mediators, name them with different constants, and do the same with the components you want them to control.
Injectors behave the same way. This explains why all of the sample programs available for Mate never have Application-level components. They always put the entire contents of an application in their own view component (such as Canvas). The reason for this is so that the Injectors can target the composite views and remove any ambiguity. It’s also just better design.
So, you have to do the same thing for Mate as well as PureMVC. But, the difference would be that you don’t have to mess with copying the Mediators. It’s much easier to replicate the behavior in your Event Maps.
Now, let’s go through all of my typical uses for a Mediator and see what the Mate equivalent is.
Enabling/Disabling Fields
In PureMVC, we can let a Mediator handle enabling, disabling, and a whole host of other operations on components. This is all fine and dandy, but it also forces us to send pretty heavy notifications when we want this behavior to fire.
In Mate, we can use either data binding or Injectors to take care of this. Data binding is easy, just bind your model to your component just like you learned in Flex 101. One problem, though, is that this isn’t “pure.” The view would have specific knowledge of the Model if I did something like:
<mx:Button label="Play" enabled="{MusicModel.getInstance().isStopped}" />
MusicModel would now be tightly coupled to my play button. Erich Gamma would roll over in his grave if he saw you do that. Good thing he’s alive.
The Injector approach, on the other hand, would be accomplished by adding to the Event Map:
<Injectors target="{MP3Panel}">
<PropertyInjector targetKey="mp3Playing" sourceTarget="{MusicModel.getInstance()}"
sourceKey="isStopped" />
</Injectors>
Note that this code is far cleaner, if a little less intuitive. MP3Panel is kept completely oblivious of the full application it’s being used in. It is loosely coupled from MusicModel. It can easily be pulled out later or used in a different way somewhere else, whether Mate is used or not.
It’s not as simple as a PureMVC Mediator, sure. You have to make sure isStopped is bindable or the Injector won’t work. You also have to learn to add specific view logic into that mp3Playing setter rather than lump it in the Mediator’s handleNotifications() method with the rest of your code.
This comes with an important win, though: It’s correct. By keeping that enabling logic in the Mediator, we lose it when we reuse the component anywhere else. That is, we’ve put UI logic in the Mediator, leaving the component too dumb to ever be separated from its PureMVC master. It wouldn’t know how to manage its own components without the Mediator!
Yes, I didn’t have to use PureMVC this way in the first place. I could have written it right the first time. The point may be that Mate enforces better programming discipline inherently, whereas PureMVC opens you up for abuse. Not the fault of PureMVC, but it can be argued that it’s an invitation to act this way. :-)
Populating Controls Without Using Binding
This is the easiest aspect to crossover to Mate. Injectors aren’t binding! While they do require the model fields to be Bindable, the Injector is doing a copy. Therefore, you never have to bind. :-)
Done.
Popping Up Dialogs and Playing Sounds
I love doing these operations with Mediators. Fire off a notification and get popups and sounds and what have you. I use Mediators because, despite the fact it’s not wrapping a “view” per se, this is UI we’re dealing with even if it’s not visual. So I use Mediators.
The bad news is that, unless we want to do some arcane programming, we can’t do this the same way with Mate.
The good news is that we can replicate this in a couple of ways. First of all, we can simply use Commands. In Mate, just like in other frameworks, Command objects cache. This means they can be stateful. (There is also an option to disallow caching, but we wouldn’t use that here.) Hence, we can use Commands just like Mediators.
That’s one way.
The second way is to use controllers. Here’s how we could do it in the Event Map:
<EventHandlers type="initSound">
<InlineInvoker method="{SoundSystem.getInstance().init}" />
</EventHandlers>
<EventHandlers type=”playSound”>
<InlineInvoker method=”{SoundSystem.getInstance().playSound}”
arguments=”{[event.soundID]}” />
</EventHandlers>
Essentially, we’re turning the events into method calls, just like a Mediator would have added. Semantically, we’re using controllers instead of Medicators. Notice we use InlineInvoker, because Mate would create two distinct models if we used MethodInvoker. This is important to remember. If you only needed a single controller for one Event Map, you could safely use MethodInvoker for this.
A small win that we get is that we no longer have to deal with the switch/case soup that Mediators impose on us. I hate forgetting break statements.
Event Maps: A First-Class Service Locator!
Mate also provides a really slick facility, akin to Cairngorm’s Service Locator, but far better! In Cairngorm, you would put all of your application’s service calls into one MXML. To call them, you pull them out from Commands, set up some callbacks, and go.
It was far less convenient if those calls had parameters you needed to substitute, though.
In Mate, you can do the same thing, but you can inline the result handlers and, better yet, substituting parameters is intuitive and easy! Check out the Services tags for usage. It will ease the burden of writing so many Commands!
Loves it.
Saving Time On Smaller Applications
Another of Mate’s great benefits is how much faster it is to write smaller applications. Let me tell you a story.
One of my favorite hobbies is competitive Scrabble. Over the span of a week some time ago, I wrote a set of applications that helped me train to be a better Scrabble player. One application let you give it a set of letters and it told you all the valid Scrabble words you could make from them. A second application tested you on it. Finally, a third application trained you on so-called “Bingo Stems,” which are a way to help you learn and memorize the most common 7-letter bingo words. (That one’s a secret!)
As a disciplined developer, I was bugged by the fact that I was writing these short little applications without using PureMVC! THE HORROR! Why wasn’t I using it? I was just too lazy to write all the boilerplate needed to write a “maintainable” application. The apps didn’t need to be maintainable. They would be done in a day and I wasn’t planning on touching them again, ever.
And it would have taken a lot longer to finish them. I needed them right away!
So, what’s the problem? The problem is that I’m all but admitting that PureMVC doesn’t necessarily make my job any easier. In fact, it makes me work harder! The only reason I use it is to make a more flexible application that can be maintained and expanded later.
But, it doesn’t make programming it any easier. And do I really want a framework where many times I would opt not to even bother using it?
Mate is different. I would have actually used Mate to write these apps without any hesitancy. Using the Services tags, I could have written my HTTP calls faster. The events that I dispatched (in the absence of PureMVC) are almost exactly equivalent to what Mate uses. I would have gotten all the benefits of the MVC framework without any of the extra mess I was trying to avoid.
In short, it would have made my work easier.
In fact, I can probably go back and refactor them to use Mate pretty easily. Maybe I will. Any Scrabble fans out there? :-)
Conclusions
I hope that I have demonstrated to PureMVC developers out there that there’s a better way to do things. Don’t be scared. You’re thinking patterns may need to change just a tad, but it only took me a couple of days to understand it — and I do believe they are better patterns of thinking.
You can have an MVC framework that makes your life easier, no matter what size the application you are building. You can get your work done faster with no sacrifices to the Almighty Design Gods ™. And, as much as I hate to admit, Mate is actually pretty fun to use, too. :-)
Treat yourself and take a look at Mate.