Tuesday, December 29, 2009

Grails Gotcha #1

Whenever you work in Grails and wonder why something like this is not working:



Check the types of objects you're trying to compare. Most likely, one of the following gotchas is keeping you busy.

1. Trying to check for containment of Strings. In case you're using Groovy's support for embedding variables in a string (using "foo $bar" notation), the resulting object is of type GString not String.

2. Trying to check for containment of byte-code-modified objects. Especially when working in Hibernate-environments, objects might not really be what you think they are. They are probably of a type like "MyClass__javaassited_36" where the objects in your list are of type "MyClass".

You might be able to change your statement to use the convenient "any { it -> // code }" method included in the Groovy JDK (Object class).

Hope it saves you from some of the headaches it's been giving me!

Remote Desktop on Mac

Did you know that Mac OS X comes with a fully integrated VNC server and client for quick and easy remote desktop access? I came across the need to use remote desktop connection with my iMac at home once I was away for the holiday season. It was pretty easy to set things up on Mac OS X so here's a quick run down of what you have to do in order to get full remote desktop access to your home Mac:
  1. Optional: Install the fantastic DynDNS client, enter your credentials and domain information. Your Mac can now be accessed using the domain registered at DynDNS even in case you only have a dynamic IP address.
  2. In case you're behind a router, make sure you enable port forwarding to your Mac on port 5900, the default VNC port.
  3. Open your Mac's system settings and open the Sharing settings.
  4. Enable Screen sharing and specify which user should be allowed to login remotely.
  5. You're now ready to go! Get another Mac and open the Finder. Choose "Connect with server" from the "Go to" menu and enter "vnc://".
  6. In case things are working properly, the login form will be displayed. The user credentials are the same that you use when working with your Mac directly (ie. without a remote connection).
Obviously, you should make sure that no user accounts with empty passwords are allowed to login remotely. Enjoy!

Tuesday, December 22, 2009

NEXT Munich

We have finally created a web presence for our new iPhone / iPod touch and Android development studio. You can find our site (German only for now) at the following location:

http://www.next-munich.com

I will start to move most of the tech-related topics to my new tech blog AppTech which is hosted on our website. I'll keep posting in English so that no reader is left behind! The first post on the new blog just presents a small piece of code which can help in case you're having flicker-issues on launch of your cocos2d-enabled application.

Hope to see you on the new site!

Saturday, December 12, 2009

Background Music & SFX on iPhone

I'm so glad that many people are sharing their findings and how they are getting things done in iPhone:

First of all, there is a super-convenient set of classes in the cocos2d package that can be used for playing background music and sound FX. The only thing I have to figure out is how I can tweak these guys to stop iPod music in case the user explicitly wants to enable in-game sound. But that's probably a piece of cake, too!

The next help comes from Tinker Blog which lists suitable file formats and conversion commands. Essentially, iPhone allows you to play one compressed file (like MP3) and several uncompressed files in parallel. Since there's only a single hardware decoder for compressed files available, not more than a single compressed file can play at the same time, though. The idea is to take your most expoensive sound and use it as an MP3 within your application (eg background music) and convert the smaller sounds (typically sound effects) to a format like "IMA4" packed inside of a "CAF" file.

Friday, December 11, 2009

Shear Transformations in cocos2d

To properly map a 2d texture onto a cube, I needed a shear transformation to properly transform the texture. Cocos2d does not support shears out of the box but this piece of code suggested by codem01 does the trick very nicely.

Keep in mind that the default shear values should be 0.0 (= no shear) and values used can be both, positive and negative and are restricted in magnitude only by your application.

You can find some more background on shear transformations on Wolfram MathWorld and on Wikipedia.

Thursday, December 10, 2009

Stupid Objective-C Mistake #1

While laying out my screen, I keep objects handy in a couple of NSArrays. Typically, I start out coding all the layouting code and retouch it once I see what's rendered on screen. Many times, objects that I try to add to my layout just do not appear - because I failed to initialize my arrays!

Since in Objective-C, a message to a nil-variable just returns nil and moves on, you dont't have any indication that something might not go according to plan. Therefore this little note to self:

First thing to do if things do not appear on screen, check your arrays initializations, stupid!

Thursday, December 3, 2009

Leak Hunting in iPhone Code

Eventually, when you're closing in on the release candidate of the software you're working on, you're probably going to check your app for memory and performance issues.

Same for me. On my current iPhone project, we're getting closer to our first beta and I felt I had neglected checking my memory usage and whether there are any apparent memory leaks in my app. Firing up Instruments, Apple's tool for analyzing Mac and iPhone software in many different ways (Memory, Disk Access, Open GL, Leaks, Core Data to name just a few), I was pretty happy with what I saw: the Leak-Detection tool did only find a couple of minor places in the code where I was leaking memory.

The output of Instruments, though not very intuitive at first, helped me identify the places in my code where I was allocating and / or retaining objects which I never released when it was time for them to be released. After patching those holes only a couple of leaking places were left that did not trace back into application code but into system APIs. Good job, I thought.

Coming from a Java background where I never had to spent a lot of thoughts to memory management (unless, of course, the occasional image = null; System.gc(); calls), switching to a reference-counted environment on the iPhone seemed to easy to be true. And sure enough I was going to find out that things are slightly more involved than checking the Leak tool in Instruments!

My colleague discovered the issue when he kept playing the game for longer than I had ever done. At some point in time, loading one of the included mini games, the application just crashed. Memory was his first thought and I also felt like it was some problem with running out of memory. Fortunately I was able to reproduce the bug and could see memory usage increase in Instruments while navigating the game.

After some time of digging for an answer I discovered an issue that was not detected by the Leak tool: cyclical references. Here I retained an object representing my scene for it to render properly while active. Within that object I created another object, however, which was retaining the scene. Once the scene was removed from screen, deallocation did not take place since the retain count of the scene did not reach 0.

How did I catch that one? A good indicator is ever increasing memory usage within your application. Monitor that while running on the phone itself to get a more accurate picture of your memory's distribution between Open GL ES memory and "regular" memory. I tried to explicitly free all my textures by calling cocos2d's [[TextureMgr sharedTextureMgr] removeAllTextures] method. Since this did not free any Open GL memory at all, something was going on. Finally, I carefully tracked memory usage using the Memory instrument when taking well-defined steps within the app. Once I had discovered a point where memory did not go back to where it was supposed to be (in case all of the memory had been free'd), I added some logging to see whether the object's I wanted to be dealloc'ed really were disposed of. That step let to the discovery of the the leak - maybe this will help you find some in your code, too!

Here's some sample implementation code to highlight what was happening:



This code kind of looks ok at first but soon you'll notice, that MyScene is never going to be dealloc'ed unless you explicitly call its' release selector twice somewhere outside of this code (which is going to lead to other problems - so don't do this!).

Assume the following code to understand why this is happening:



As you will probably know from Apple's documentation, whenever you're using alloc / init to create an instance of a class, you've implicitly retained the object. You have to explicitly release the object to properly dispose of the object. Now pay attention to the object's retain count:

1. The call to [[MyScene alloc] init] gives you an implicit retain count of 1.
2. Additionally, MyObject retains the allocated scene thus increasing its' retain count to 2.
3. Once [scene release] is called, the retain count is reduced to 1.

As you can see, the retain count is not going down to 0 as it should because of the retain by MyObject. Since MyObject only releases its' reference to MyScene in dealloc, this is not going to happen unless you explicitly send the MyObject instance the release selector.

The easy fix: if MyObject only lives as long as the scene is living, just don't retain the scene. It's going to be alive as long as MyObject is alive so there is not going to be a problem.

If you think this is happening to you, too, make sure you log the retain count of the object in question at appropriate times (whenever you think this object should be dealloc'ed but isn't). You can do this with a single line of code:



Hope this helps you find the pesky cyclical memory leaks. When is there going to be an app for that, too?

Did you find any other common patterns of leaks that are not detected by Instruments? Share your findings in the comments! I'm surely going to be thankful but so are probably all the other readers / Google users.