Monday, November 14, 2011

Apple and non-public APIs

We recently got a rejection from Apple for using a non-public API. Google was not a big help on this one, so here's the story of how we tracked it down.

We found that your app uses one or more non-public APIs, which is not in compliance with the App Store Review Guidelines. The use of non-public APIs is not permissible because it can lead to a poor user experience should these APIs change.

We found the following non-public API/s in your app:

appName
setAppName:
Step 1: Find in files

There's a dropdown when typing into the search bar in XCode that lets you search in frameworks. Unfortunately we got no hits with this search, so that tells us the private calls are not in our code.

Step 2: Command line tools
From the rejection mail:

Additionally, one or more of the above-mentioned APIs may reside in a static library included with your application. If you do not have access to the library's source, you may be able to search the compiled binary using "strings" or "otool" command line tools. The "strings" tool can output a list of the methods that the library calls and "otool -ov" will output the Objective-C class structures and their defined methods. These techniques can help you narrow down where the problematic code resides.

otool and strings are tools that seem to be on the global path, so you can type them into the command line from any directory. The trick is you have to figure out what to run them on. XCode 4 tends to put things in strange directories, so here's a shortcut to finding the actual file you want.


Find your app under "Products" in XCode and right click on it to select "Show in Finder". This will open up a finder window where your .app file lives. If you run otool or strings on this file it will not work. Right click on your .app file and select "Show Package Contents". Then find your executable file and copy it to somewhere accessible.

Once in Terminal and in the right directory, the two commands to use are:
otool -ov ScribbleWormHD
strings ScribbleWormHD
These will output a ton of stuff. You likely won't be able to navigate it without using command-F to search for the strings that Apple complained about. In our case otool did not give us anything useful. It would have been easy to track down the problem if it had, because otool will tell you what called the offending function. Strings just outputs a list of every string used in your project. We managed to get a hit with that, so at least we had a way to test if any changes we made would fix the problem.

* NOTE: strings did not work for us at all in Snow Leopard. It only worked in Lion.

Step 3: Head Scratching

So the calls to setAppName were not in our code, and we had no tool telling us directly where the calls were. Sometimes debugging degenerates into informed trial and error. We only have two middleware libraries in Scribble Worm: Flurry and Admob. We started with Flurry on a hunch and removed it from our project as a test before running strings again. This time we were clean.

So we went to the Flurry site and found that they are on version 3.0 while we shipped with 2.8. One upgrade later and another run of strings and we were ready to submit.

Saturday, November 5, 2011

Design Patterns in GHEngine, Part 1

One of the major design goals in our engine is to have as small as a codebase as possible. To do this, we want to re-use as much code as possible. A Golden Hammer in programming is a tool that gets overused and applied to many problems even when it is not a good fit. We have a small set of design tools that are so generic we can use them in all sorts of places. It's a good model if you can have a unified design: avoid duplication by extracting the shared work and making it available to all users. The danger of course is we can end up with the bad definition of golden hammer if we're not careful.

The Controller

class Controller {

virtual update(void);

virtual onActivate(void);

virtual onDeactivate(void);

}

A Controller is something that updates. Our renderer, physics, and input handling are controllers. We can store these controllers in a sorted list for updating, and we can dynamically add or remove controllers on the fly. Instead of having a big update function where we say "do this, then do this, then….", we have a single function that looks like this:

void runFrame() {

for each Controller, call update();

}

Note that Controller does not take any arguments at all. Once you start adding arguments, you start making assumptions about all possible Controller subclasses, and that list can grow to the point where you are passing a lot of stuff that most controllers don't care about. If a Controller needs to access something like the current time, we pass in a time value reference in the constructor.

By having this dynamic list we can avoid iterating over objects that don't need to do anything. If an entity like a player needs an update it can add a Controller to the list. If an entity like a tree does not need to do any work, it can avoid the list. Just touching the memory of each entity in a large world can become a serious performance issue even if no work is being done.

State Machine

class StateMachine {

addTransition(trans, state);

removeTransition(trans, state);

setState(state);

}

class Transition {

virtual activate(void);

virtual deactivate(void);

}

A StateMachine is used to change behavior based on whatever influences we want. Instead of defining each state as a class, we define a state as a set of Transitions into and out of that state. The most common Transition used is a ControllerTransition, which is used to add Controllers to the update list. An example Transition is a MusicTransition, which plays a song while it is active. We can create one of these and add it to the main menu state, then whenever the main menu is shown music plays.

class MusicTransition : public Transition {

activate() { start playing music }

deactivate() { stop playing music }

}

Another use for StateMachine is players. We can use a ControllerTransition to have an input handler active while the player is in the alive state. Then when the player dies we shift him to the dead state, and the ControllerTransition removes the input handler from the update list.

Events

class Message {

identifier messageType

payload messageArguments

}

class MessageListener {

virtual void handleMessage(Message);

}

class EventManager {

addListener(MessageListener, message identifier);

removeListener(MessageListener, message identifier);

broadcastMessage(Message);

}

Events are something that happened, that something else cares about. They are an alternative to having a bunch of different managers that know about the inner workings of some set of objects. We also use them for communicating between threads and for sending information over a network, as they can be stored up and sent later. The real flexibility comes into play when we start data driving message loading, adding listeners that change state to state machines, and allowing out GUI to send loaded messages.