[UIImage imageNamed:]

December 10, 2009 · Posted in dev · 1 Comment 
UIImage *myImage = [UIImage imageNamed:@"pony.png"];

This is probably one of the most convenient methods I’ve ever come across. Feed it a name and it will return an image. Better yet, it handles caching for you automatically so that you don’t have to. Notice something about it though? There’s no alloc, meaning you shouldn’t call release. If you can’t call release, how do you get your memory back? This isn’t a big deal when using Mac OS X’s older brother, NSImage, since your average computer these days ships with several gigabytes of memory as opposed to the paltry 25MB or so that most iPhone apps are limited to. If you’re dealing with a lot of images on the iPhone though, this hands-off caching approach is going to cause problems.

The first obvious solution is to just avoid the convenience method and manually alloc and load each image with its full path:

UIImage *myImg = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/pony.png", [[NSBundle mainBundle] bundlePath]]];

That’s not awful for loading an image or two, but if you’re going to load many images, why not encapsulate this in something more elegant? Since such a method would be useful application-wide, it furthermore makes sense for the method to exist in its own application-wide class, rather than just stuffing the method willy-nilly into whatever class you’re working in. Actually, if you’re going to go to the trouble of creating a new class just for a convenience method, why not make it do other neat things? Let’s do that.

Phantom Functions

June 10, 2009 · Posted in dev · Comment 

Not that they’re very spooky, but function calls that don’t do anything can be a real time-sink. The call in question: glPolygonOffset(), a terribly useful function which I was using to prevent Z-fighting. Everything worked as expected in the iPhone simulator, but nothing happened when run from the real hardware! After an hour of searching through the code and documentation, it turns out the answer is pretty straightforward: polygon offset is not supported by the hardware.

The fact that the compiler didn’t kick out a warning or error would seem to suggest that the feature is available in later models. My test platform uses PowerVR’s MBX Lite 3D GPU, as do all models up until Monday’s announcement. Still, Apple is able to tailor the SDK’s header files exactly to their devices capabilities, so it’s a touch frustrating. On the bright side, there’s a workaround for coders who needed glPolygonOffset to draw edge geometry:

        #define EDGE_OFFSET 0.00001

        glDepthRange(EDGE_OFFSET, 1.0);
        /* draw all non-edge geometry */

        glDepthRange(0.0, 1.0 - EDGE_OFFSET);
        /* draw all edges */

There’s a couple more good ideas actually, but the above code works fine for a low-power device.

I am an Idiot

June 2, 2009 · Posted in dev · Comment 

Learned two things today:

1). An array of pointers is possible without stuffing it inside a struct. GLuint **texturePtr; creates a pointer to a pointer, and since a pointer can easily point to an array allocated with new, it follows that such a pointer could point to an array of pointers pointing to more stuff. Lesson learned.

2). The statement int allocSize = n * 16 – 8; GLfloat *vertices = new GLfloat[allocSize]; is only useful when n > 0. Whoops.

 

Update: It’s done! This most productive weekend has turned out a mostly-functional lightweight OpenGL-based sprite library.

Pointing Fingers

May 31, 2009 · Posted in dev · Comment 

An array is useful, and a pointer is useful, and if a pointer pointing at a dynamic array is more useful yet, then surely a dynamic array of pointers must be made of awesome sauce. Cocoa has spoiled me a bit, what with NSMutableArray acting as just the ticket, but at a probable expense. Complexity and abstraction layers are the enemy of framerate, so I’ve turned to C arrays to solve a time-sensitive problem. After a couple hours of poking around, I’ve found a solution, though I can’t tell if this is elegant, hackish, or just downright silly:

typedef struct {
    GLuint *texturePtr;
} TextureStruct;

TextureStruct * allTextures;

So what’s going on here? Originally, the plan was to have an array of GLuints to keep track of loaded textures (there’s no sense of loading the same data twice on a handset with little memory after all). The array doesn’t know how big it will be at compile time, and more importantly, it might grow or shrink during runtime, so a declaration of GLuint * texture; seemed like the logical thing. Problem is, arrays hold data, but this array must hold pointers. Wrapping the pointer inside a struct and then declaring a pointer/array of the new structure does the trick, but it feels crude.

It’s a strange feeling though, that the actual data doesn’t have any central location. A texture is loaded when an object needs it, but the texture doesn’t belong to the object, nor does it belong to the above structure/pointer/array monstrosity. It just hangs out.

Object Chains

January 30, 2009 · Posted in dev · 1 Comment 

This almost certainly isn’t a first, but I discovered a neato trick. Let’s make a chainable class, called Chain. It would contain two instance variables (at least) called next and previous, also of the Chain class. Its init method would go something like this:

- (id)initChainOf:(int)n
{
    if(self = [super init])
    {
        // Setup instance variables, etc. Then:
        n--;
        if(n > 0)
        {
            next = [[Chain alloc] initChainOf:n];
            next.previous = self;
        }
        else
        {
            next = NULL;
        }
        previous = NULL;
    }
    return self;
} 

Call Chain *myNewChain = [[Chain alloc] initChainOf:5]; and you’ve got five new objects linked together. After the first object is initialized, it decrement the link number and initialize another link if the link number is above zero. The next link repeats the process until the link number reaches zero. The instance variable previous (more explicitly called self.previous) is initially set to NULL, but if the link has been created by a parent link, it will manually set next.previous to self, which alone is a slightly confusing statement. Clean up works similarly:

- (void)releaseLink
{
    if(next)
    {
        [next releaseLink];
        [next release];
    }
}

One link will call the next to release its link, which will then call to release its next link, etc. No object actually releases the self.next object until it has told its own link to do the same, so all the releases actually cascade down. The whole thing can be unravelled with two lines:

[myNewChain releaseLink];
[myNewChain release];

Recursive programming is one of those things that’s crude is misused but elegant when done right. I’m not sure which the category the above falls under, but maybe it’s too bare bones to qualify yet. With the above setup, you lose some of the control that NSArray and its mutable counterpart provide. On the other hand, it’s probably leaner and faster at what it does if you don’t need all that control. Sorting is non-existent, inserting objects between links (or inserting any object at all that isn’t a Chain) becomes problematic, but its behaviour is just what I need right now.

Mirror, flip, inverse, invert, stop drop and roll

January 11, 2009 · Posted in dev · 2 Comments 

Not having much to compare it to, I can’t honestly say how well the developer documentation stacks up against those available on other platforms. It certainly serves me well enough, and is worlds apart from what came with MPW. The day that MPW finally started working was a small miracle; this was before Google had an answer to just about everything (great instructional video too), and most libraries assumed you were using CodeWarrior anyway. At any rate, the reason for today’s post: for everything not spelled out by the developer docs, there’s Google.

After spending a good hour trying to trackdown a [UIImage reverse] method (there is none), I’ve boiled it down to a working block of code. Best of all, it’s short! So here’s to you, Googlers, I’m putting it on the internet in hopes that another dev finds it useful. The following snippet will horizontally reverse/flip/mirror a UIImageView:

UIImageView *myView = [[UIImageView alloc] initWithImage:myImage];
myView.transform = CGAffineTransformIdentity;
myView.transform = CGAffineTransformMakeScale(-1.0, 1.0);

That’s it. To flip it back:

myView.transform = CGAffineTransformIdentity;

Not so scary anymore! So what’s going on here? Get your answers from a more authoritative source. It’s a good read about a powerful property, and highly recommended for anyone who doesn’t want to create two or ten different versions of the same image at different rotations.