The other day I was preparing our new game for release and while tests using the debug build worked beautifully the game suddenly starting crashing in a weird situation that was difficult to discover when run using the release build.
Narrowing it down to the fact that it worked without optimization but crashed with any level of optimization I figured some object that should be released hadn't been released, or released to soon, or maybe not released at all.
This introduced me to the great feature "Zombie objects" for the first time. Zombie objects are not enabled by default so you have to enable this in the scheme configuration of your project. Zombie objects keep released objects in memory so instead of getting an error like "EXC_BAD_ACCESS" you can see what kind of object your code is trying to access. Great, isn't it?
So now I could see what object my code was trying to access when it crashed and also where in the code the crash happened instead of seeing just a block of assembler code.
ARC, Automatic Reference Counting, is great new feature of Objective-C that manages the pointers for you and releases the objects when they are not longer referenced to. However, it is different from Garbage Collection and apparently we need to take care in certain situations otherwise error likes this might happen.
Maybe this is only because my lack of knowledge, or maybe unknown "feature" of ARC. Anyhow, I want to share this with whoever finds their way to this blog.
I the code causing trouble I have a matrix of pointers, like this:
__strong Tile *_board[13][13];
Actually you don't need the keyword __strong because it is default but I put it there for clarity. This means that this matrix will strongly hold on to whatever Tile pointers I put there. Good, now we want to do something with these pointers. Like finding out where row of tiles start vertically.
while (row > 0) { Tile *t = _board[row-1][column];
if(t ==
nil)
break;
row--;
}
This work great in debug mode (no optimization) but crashes in release mode with code optimization. Well, it doesn't crash the first time it is run but the second time, after it's gone out of scope. Apparently all the Tile objects iterated over is released when the method goes out of scope.
Changing the code to this solved the problem.
while (row > 0) {
if(_board[row-1][column] == nil) break;
However, this seem to only apply to while loops. For loops does not cause the same behavior using ARC. I think I will head over to Apple's documentation and see if I can find a reason for why this is the case...