Friday, October 30, 2009

Running Actions in cocos2d during onEnter

I just discovered a requirement in the onEnter method when you try to run a duration-based Action in cocos2d. Whenever you're trying to do something like this within the onEnter method of a subclass of Layer:

[node runAction:[FadeIn actionWithDuration:1]];

make sure you call the super class' onEnter method. Otherwise the action will not perform what you try to achieve. Working code looks like this:



Hope this helps someone and saves some time!

Thursday, October 29, 2009

Note to Self on Void Pointers and CallFuncND

This is no news to anyone except for people who have never been exposed to void pointers (void*) before. Coming from a Java-background, I never had the opportunity (or dare I say hassle) to deal with pointers, obtaining memory addresses and de-referencing those. Whenever I was confronted with C / C++, I tried my best not to dive too deep into that matter.

Now in Objective C, I finally wanted to get rid of a compiler warning I was getting because I was dealing with void* as a data type. Basically, void* is a pointer to some data in memory of which the type is unknown to the compiler. Therefore, any address to some data in memory can be stuffed into a variable of type void*. Both of the following is valid:

void* data;
int i = 5;
float f = 6.5;

data = &i; // first assignment: works
data = &f; // second assignment: works, too

Now to get back to the data you stuffed inside, you cannot just de-reference it just like that. You need to cast it to the proper pointer type of the data that is stored at the particular address you're pointing to. In other words, you'd have to do the following (continuing the code above):

int* iPtr = (int*) data; // if data contains &i
float* fPtr = (float*) data; // if data contains &f

Since cocos2d uses void* as the data type to piggy-back any kind of user data within a CallFuncND action, I at least had to get that straight!

Sunday, October 18, 2009

Mac OS X auto-starting Tomcat

To complete my dive into continuous integration with Hudson I wanted to have Tomcat (the Servlet Container of choice) auto-run in the background on my Mac box.

First of all, download the latest Tomcat distribution from the project's homepage. Now change the script files in its "bin" directory so that they can be executed using "chmod +x *.sh". This is all you have to do to get a working copy of Tomcat on your system. Give it a spin by executing the startup shell script and navigating to "http://localhost:8080/". You will already notice that the startup will cause an icon to appear in your dock that you might rather not want to see (first of all it's ugly and clutters the dock and secondly, it doesn't provide much functionality anyways). We'll get rid of that icon a little later.

Now to have Tomcat startup automatically on system start, you have to create an entry in "/Library/StartupItems". By default, the directory is protected and you're not allowed to copy anything here. Use the Finder to change the permissions of the directory and grant yourself rights to read and write the directory. Now create a new directory "Tomcat" and place the following two files inside.

File "Tomcat":
#!/bin/sh

. /etc/rc.common

export CATALINA_HOME=/Applications/apache-tomcat-6.0.20
export JAVA_OPTS=-Djava.awt.headless=true

StartService ()
{
ConsoleMessage "Starte Tomcat Server"
su -c $CATALINA_HOME/bin/startup.sh
}
StopService ()
{
ConsoleMessage "Stoppe Tomcat Server"
su -c $CATALINA_HOME/bin/shutdown.sh
}
RestartService ()
{
ConsoleMessage "Starte Tomcat Server erneut"
su -c $CATALINA_HOME/bin/shutdown.sh
su -c $CATALINA_HOME/bin/startup.sh
}
RunService "$1"
where you substitute "" for the user account that should be used for building your iPhone app (the name of your home directory should work). This setting is crucial as Xcode will not build your project unless your running build as the user whose key chain contains the iPhone developer certificate. If you're trying to build using a different account you will get error messages saying that a suitable provisioning profile could not be found.

File "StartupParameters.plist":


These files will allow Tomcat to automatically launch when the system starts. To make this work, give execution rights to the file "Tomcat" using "chmod +x Tomcat" in directory "/Library/StartupItems/Tomcat". Now change the ownership of the files and their folder using the command "chmod -R -v 0:0 Tomcat" in directory"/Library/StartupItems". This will give ownership of the files and the directory to root - a requirement by the service launcher.

You can now test whether things went smoothly by executing the command "sudo SystemStarter start Tomcat". If things go well you will notice that no icon appears in your dock on launch. This is due to the Java parameter "-Djava.awt.headless=true" that we specified in the script "Tomcat" above. If you would like to keep the icon, just comment the line using a "#".

If things do not go well it's most likely due to some missing permissions. Check the logs in the utility application "Console" that you can find in "/Applications/Utiltities".

This post followed the German description by Kai Surendorf and adjusted things where appropriate. The "java.awt.headless" tweak was found on Hardy Ferentschik's blog.

Now I'm off to write a small Hudson/Growl integration app since the Java-based notifier available on Hudson's site didn't seem to properly invoke Growl on my machine. Maybe the recent Growl update or Snow Leopard broke the tool.

Stay tuned!

Follow-up on Versioning

While working with Hudson today and trying to get a CI server up for automated iPhone builds, I came across an article by Dave Murdock regarding versioning of iPhone apps. Turns out I did things slightly different to what is the - apparently - recommended behaviour:
  1. Use "CFBundleVersion" for your build number
  2. Use "CFBundleShortVersionString" for a version number like "0.1"
  3. Concatenate those strings within your application
This approach seems to be the standard behaviour in Mac OS X applications.

For integration with Hudson it also became apparent that updating the version number on Hudson builds using Apple's agvtool from within the Hudson build script was very straight forward and did not require additional files. So I'm basically using the Hudson build script as outlined by Michael with the versioning setup explained by Dave. Sweet!

iPhone and Unit Tests

Finally, following a series of posts on Luis de la Rosa's blog, I have Google Toolbox for Mac up and running my Unit Tests for iPhone.

Here's a quick note in case you choose to download the latest code from SVN instead of downloading the pre-packaged v1.5.1 from Luis' page: in addition to the files he copies to the sample project, you need to copy two additional files, "GTMObjC2Runtime.h" and "GTMObjC2Runtime.m", into your "UnitTestFramework" group within Xcode. With these files included, your build of the UnitTest target will work successfully.

Now having a look at the continuous integration suggestions by Michael Nachbaur. Let's see whether I can get a Hudson instance running and packaging both, my test targets and the final application.

Thursday, October 15, 2009

Automatic version numbering in Xcode

Here's a nice piece on automatic version numbering from within Xcode. The article details almost all the work you have to perform to get automatic versioning up and running.

Here are the missing pieces:
  1. Place the Xcode config file in the root of your project.
  2. In your Info.plist file change the value for "Bundle version" to something like "0.1 (${CURRENT_PROJECT_VERSION})" - depending on your choice for the variable in the config file.
With those two things in place, versioning should be up and running in no time. Thanks, Diego!

Friday, October 9, 2009

What a Fight!

I spent the whole day migrating a Grails-based application from a Linux / MySQL / Apache infrastructure to Windows Server 2003 / MS SQL Server / IIS. Here's my tale of this migration ...

Objectives:
1. Get Grails to work with MS SQL Server 2005
2. Integrate Tomcat into IIS so that no additional ports have to be opened on the server

Starting the day with the MS SQL Server migration, things went pretty smooth. I set up a custom environment "mssqlProduction" in DataSource.groovy using the driver class and connection string as outlined on the MS driver's homepage. Afterwards, I copied the MS driver jar sqljdbc4.jar into the project's "lib/" dir and generated the first .war file of the day (using "grails -Dgrails.env=mssqlProduction war" because of the custom environment).

Logging into the server, I installed Tomcat 6 in Program Files (x86) and encountered the first issue: the Tomcat service did not launch. Turns out that Tomcat 6 is delivered with 32bit binaries but since my system is running a 64bit OS, the binary failed to execute. Once I had replaced the binary with the 64bit version (which can be downloaded right from Tomcat's SVN), things were running smoothly.

Next step: creating a new DB and user account in MS SQL Management Studio so that Tomcat is able to connect. This worked like a charm (once I figured out how MS SQL Management Studio works). After I had adjusted user name and password in DataSource.groovy, I attempted the first deployment into Tomcat. As the Grails project uses the domain classes "User" and "Rule" and Grails automatically maps those to the tables "user" and "rule" respectively, the DB eventually gave some errors during deployment. "user" and "rule" are both reserved keywords within MS SQL Server 2005 and thus raise issues in SQL statements. Changing the "mapping" closure for each of the classes and adding "table 'new_table_name'" statements fixed that issue.

Without any further problems, the app was up and running within Tomcat using MS SQL Server as its DB. Sweet!

Since I did not want to open up more ports on the server, the second task of the day was integrating Tomcat with IIS 6. I basically followed the instructions given on the Tomcat website. Obviously, this didn't work the first time around and I had to go back and forth verifying the different Registry settings and the changes that had to be made in other places. My key take away: rename the redirect file to exactly what's proposed in the How-To as you're bound to run into problems if not.

Eventually, the Tomcat ISAPI filter in IIS came up green and was launched successfully. The problem, however, was that it was only invoked properly for certain virtual directories defined within IIS but failed to forward any requests to Tomcat (instead, I was greeted with Service Unavailable messages in my browser for any site I tried to access). Turns out that I had to configure the App Pool containing the jakarta virtual directory to have Local System as the account to run with. Now that solved the problem of the filter not redirecting any traffic to Tomcat.

However, when trying to access one of the Tomcat-managed sites, IIS was constantly asking me for my Windows logon credentials. Obviously something was off. After a lot of unsuccessful digging, I eventually changed the security settings for the isapi_redirect.dll to grant execute permissions to the IIS user account that was configured for anonymous browsing of the jakarta virtual directory. Another issue down!

Server's up and running now though I have seen a couple of things that I want to take another look at:
  • Currently, all filter files except for the dll (workers.properties, uriworkermap.properties, isapi.log) are stored in root directory as I was really struggling to get rid of the dreaded red arrow that kept appearing in IIS' ISAPI filter dialog.
  • Regular HTTP-authentication requested by a Tomcat-served page does not seem to work correctly.
Let's see whether we can crack those nuts, too.

Wednesday, October 7, 2009

Properties vs Instance variables

So being able to work with properties in Objective-C is very nice but there are subtle things to keep in mind when using them.

I just came across a problem which cost me about 30 mins of my time. In one of my methods I was (supposedly) assigning an object to one of my properties. The property was marked with retain so that it was supposed to be retained unless re-assigned or the owning object is dealloc'ed. Unfortunately, in a different part of the code, accessing that very property threw an exception.

Turns out that I hadn't yet mastered the subtle difference between properties and instance variable. Assume the following code sample:

@interface Foo : NSObject {
NSString* bar;
}
@property (retain) NSString* bar;
- (void) test;
@end

@implementation Foo {
@synthesize bar;

- (void) test {
NSString* str = @"Test";

// this assignment does not use the synthesized setter
// but accesses the instance variable directly
bar = str;

// same here
self->bar = str;

// only this way of accessing uses the setter and thus
// retains the object reference
self.bar = str;
}
}

First of all I did not know about the arrow-way of accessing instance variables, secondly I thought access as displayed in the first assignment would use the setter method.

Hope this helps in case you're ever going to scratch your head because of this!

genstrings / copystrings

Setting up an iPhone project I came across some weird behviour with genstrings / copystrings commands.

In principle, genstrings is responsible for searching your source code for macro statements of the form NSLocalizedString(@"keyword", @"description") and will place an entry in a (UTF-16) text file called Localized.strings for each macro it discovers.

Now if you use this command to generate the file, add it to your project, localize it (by Right-clicking on the file, choosing "Get Info" and "Make Localizable") everything works great. If, however, you create that file manually (in my case using TextWrangler) the copystrings command will fail during the build process. I'm quite sure that this is somehow related to file permissions on Mac OS X but couldn't quite figure out what was going wrong. After all, the file permissions that you could see in Finder were the same either way.

If anybody else came across this and solved it (got manual creation of that file to work), let me know!

Thursday, October 1, 2009

iPhone drawing

I'm not sure whether I just got bad at googling things but apparently, when I first researched bits and pieces about rendering stuff on iPhone, I did not find the way of rendering I was so desperately looking for:

Instead of diving into OpenGL ES right from the start, I was looking for a rendering mechanism similar to what J2ME offers: subclassing Canvas, overriding the paint() method and adding all of your drawing calls to that method.

For iPhone I expected to find a similar way of rendering and, sure enough, came across Quartz as iPhone's 2D rendering library of choice. What I did not find, however, was the part where I subclass and add the statements to a particular function in my code. Now, reading the first few lines of Dave Mark's and Jeff LaMarche's chapter on Quartz and OpenGL ES (from their book Beginning iPhone 3 Development), I finally found the missing piece:

  1. Subclass UIView
  2. Override drawRect:
  3. Add Quartz-calls

If you're wondering where you can get a handle to the Graphics context (that you'll get automatically as an argument to the method in J2ME), you use UIGraphicsGetCurrentContext() to get a handle to it.

Maybe this post looks dead-simple, I just hope some people will find it in their quest to discover the information I was looking for myself :-)