2012-07-28

Objective-C Literals

Xcode 4.4 ships with a new version of LLVM that supports a host of new syntactic sugar around collections. You used to have to write this:


NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];

Now you can write this:


NSDictionary *dict = @{ @"key1": @"value1", @"key2": @"value2" };

There’s a similar syntax for arrays. There’s also an easier way of subscripting. This is the old way:


id obj = [dict objectForKey:@"key1"];

This is the new way:


id obj = dict[@"key1"];

This all sounds wonderful in theory. Less typing! However, in practice:

  • Apple state in the release notes for Xcode 4.4 that this new syntax only works in OSX, but I’ve successfully used array, number and dictionary literals in an iOS app.

  • Attempts at subscripting arrays or dictionaries in iOS fail with a “bad receiver type” compiler error.

  • Subscripts work in OSX when compiled for “running”, but fail with the same compiler error when compiled for “archiving”.

As none of this seems to be documented anywhere (except on the LLVM website, which of course makes no mention of OSX or iOS and has no information on which bits of the syntax are available on which platform), I’m going to assume that subscripting is, at least for the moment, broken and unusable.

2012-07-10

The Retina MacBook Pro

I got me one of them there new “retina” MacBook Pros. It’s the stock 2.3GHz 15” model with 8GB of RAM and a 256GB SSD. Here’s a miniature review. Disclaimer: it’s a work-supplied computer, so I’m using it exclusively for development and didn’t have to pay for it myself.

First off, the bad. Finder won’t start with my Acer monitor plugged into the HDMI socket; the screen turns blue and the computer hangs. This is odd, as the monitor works fine with my previous 2009 MacBook Pro, and works fine with the retina model if I plug it in once the computer has finished booting.

It occasionally does weird things to the iPhone simulator. This may or may not be related to the new hardware. Xcode is so relentlessly buggy that it is difficult to tell. However, I haven’t experienced these particular problems on any of the other 3 Macs I use for development, so that narrows it down a little. The iPhone-style surrounding skin sometimes disappears, leaving me with a title bar informing me of the simulator’s build number. It also has a habit of placing the iPhone’s screen about 100 pixels below and to the right of where it’s supposed to be, which looks odd when the surround does actually appear. In Xcode itself, hovering over a keyword results in the tooltip floating somewhere near the top of the screen instead of next to the mouse.

The lack of an eject button means the Ctrl-Shift-Eject shortcut I’ve used for the past year or so no longer puts the display to sleep, so I’m forced to use the keychain app to lock the computer instead.

The massive resolution seems to tax the GPU when it has to throw a lot of pixels around. Scrolling a webpage within a large Safari window is noticeably jerkier than doing the same on either my personal 2011 13” MacBook Pro or the 2009 15” MacBook Pro I was previously using at work.

The keyboard is somehow different. I’m not sure if it’s that the keys have a different texture than my previous Macs or if they have an even lower profile, but I’m finding it a little awkward to type on.

Now the good!

This computer is fast, mostly due to the SSD. It boots in seconds, and apps typically load before their icons have finished their first bounce. It compiles my current project in half a dozen seconds, compared with roughly a minute on the 2009 laptop. VMWare resumes a suspended Windows session in no time at all. This is the first SSD I’ve owned and the performance is really stunning. I’ve held off from buying one because I’m tired of being an early adopter and getting hardware that’s unreliable or overhyped, but seeing this drive in action has convinced me to get one for myself.

The screen is gorgeous. I was concerned that non-retina apps would look horrible on the upscaled display, but although there’s a difference it isn’t one that bothers me. It manages to make the Xcode storyboarding system even more awesome than it was before, by making it possible to see each iOS view clearly even when zoomed out to 25%. Text is amazingly crisp, which is marvellous when you spend 8 hours a day in front of a text editor.

It’s now possible to use the iPhone simulator in retina mode and have it appear on-screen at the same size as the standard mode. Dragging it over to a standard-resolution second monitor causes it to automatically halve its resolution but stay at the same physical size. Handy. If the simulator starts up on the second monitor it adopts the same enormous proportions as it would on a non-retina Mac.

And now for the indifferent.

The built-in HDMI port means I’ve ditched the DisplayPort to HDMI adaptor that I was using previously. However, as the new model doesn’t include an ethernet port I’ve got a Thunderbolt ethernet adaptor plugged in instead.

As it’s a work machine I’ve no use for the USB3 or other updated sockets, so I can’t comment on whether they’re an improvement or not. Ditto for new speaker design; I don’t use them. The same goes for the new lightweight form factor, too. I prefer the 13” models, so for me a 15” laptop is oversized no matter how thin it is (and it is very thin). When Apple get around to releasing a 13” Pro with a retina screen I’ll probably end up getting one for myself.

Is it worth buying over the standard resolution model? Yes. Being able to test websites and apps on the latest displays is definitely worthwhile. You’ll lose the optical drive, but that’s mostly worthless now anyway. You can always get an external drive if you really need one. You’ll also lose the ability to upgrade the RAM or replace the battery. I’m not concerned about the battery life - I’ve treated my 2006 white MacBook’s battery well and it’s still working after 6 years - but the RAM might be more of an issue. I got the 8GB retina model, which runs Windows 7 x64 and Visual Studio 2010 in VMWare and Xcode with no issues at all. However, if I were stumping up my own money for the laptop I’d have opted for the 16GB model. I’ve had to upgrade the RAM in all of the Macs that I’ve owned in order to keep the hardware viable over time, so the extra is undoubtedly worth it.

Is it worth it if you’ve already got a decent Mac that doesn’t waste too much of your time while it compiles? Honestly, not really. The most impressive difference between the new model and my own laptop is the I/O performance, which is solely down to the SSD. My next Mac will have a retina display, but for the moment I’m just going to fit an SSD to my current laptop.

2011-08-11

Really Bad Eggs - Objective-C Edition

The Objective-C version of Really Bad Eggs is coming along nicely. I’ll try to get some screenshots and maybe a video up, but in the meantime here’s some stream-of-consciousness pontificating on the port so far.

When I wrote DS code I used to complain about the lack of a debugger. I’ve written most of the Objective-C version of Really Bad Eggs whilst out and about on a Windows laptop, so I haven’t had a debugger or even a compiler. Despite the lack of tools and the game being my first Objective-C program it’s working well so far. Rewriting the code in a new language has allowed me to re-examine a lot of the original ideas. In some cases I’ve refactored both the C++ and Objective-C code to be simpler or more versatile. In others I’ve used features of Objective-C to improve on the original code.

Bug Fixes and General Improvements

The DS’s representation of incoming garbage eggs was inaccurate due to a typo. I’ve fixed this in both versions of the game. I’ve also improved the placement of garbage eggs that are dropped into the grid.

Garbage eggs are always dropped into the columns with the least eggs first. The (simplified) algorithm looks like this:

  • Get a list of columns and their heights, sorted in ascending order by height (insertion sort).
  • Add the leftmost column to the list of “active” columns.
  • While there are eggs to place:
    • Place a garbage egg in each active column.
    • If the column to the right of the last active column has the same height as the last active column, add it to the active column list.

It essentially fills the grid from bottom to top as though it were pouring in water.

There is a subtle problem with the algorithm. The sorting system produces a list of columns that are sorted by height and column index. In SQL, it would look like this:

SELECT
    columnHeight
   ,columnIndex
FROM
    columns
ORDER BY
    columnHeight ASC
   ,columnIndex ASC

If columns 0, 1, 2, and 5 are of height 2, whilst columns 3 and 4 are of height 1, and we add a garbage egg, we know that the egg will be added to column 3. Here’s the column state:

        000  0
        000000
        ------
Column: 012345

Here’s the sorted data:

Column: { 3, 4, 0, 1, 2, 5 }
Height: { 1, 1, 2, 2, 2, 2 }

The first column to receive an egg will be column 3, as it is the left-most column in the sorted list.

This predictability means that advanced players can start using it to their advantage. They can drop a block here because they know they’ve got an incoming garbage egg and want it to go there. They can change their plans because they know what’s going to happen next. To prevent this, the sorting algorithm now randomises columns of the same height within the sorted array.

Memory Management in Objective-C

Memory management is a pain. I can see exactly why Apple have implemented reference counting the way they have. I’ve worked extensively with low-level memory management in C++ due to the combo attack of the DS’ tiny stack/slow CPU. The combination makes both smart pointers and stack-based objects mostly unusable, leading to the same questions time and time again:

  • If I call a function, who owns the memory it allocates? Do I delete it or not?
  • Does this function expect to receive an existing block of memory that I allocate or will it allocate its own?
  • When writing functions, should I allocate memory or should I expect it to be allocated in advance?
  • Should I return allocated memory via the return statement or via a pointer-to-a-pointer passed as a parameter?
  • Should I return an object on the stack and hope RVO kicks in, or should I return a pointer to an object on the heap?
  • Should functions receive and return pointers or references to objects?
  • If an object is told to store a pointer to another object, should it store the pointer or a copy? What if the pointed-to object changes during the lifetime of my object?

I’ve become used to considering these issues every time I work with memory in C++, but Objective-C tries to solve the issues itself. Mostly it uses conventions to suggest the correct approach. Functions with “new” or “init” at the start of the names, for example, will retain the returned object and increase its reference count. The caller therefore becomes the owner of the object. Convenience methods, such as NSArray’s arrayWithObjects method, return autoreleased objects. These are released automatically by the Cocoa framework when the current iteration of the application’s state terminates. If the creating code needs them around longer then it needs to retain them. Collections retain objects added to them, so they can be deemed to be the owners of those objects. It is the responsibility of the object’s previous owner to ensure that he releases the object.

Getting the hang of the conventions is tricky, particularly when dealing with frameworks like cocos2d which aren’t the best architected examples I’ve seen. There are a number of edge cases, too. Suppose you retain a reference to object A, which creates and retains a reference to object B, which itself creates and retains a reference to object C. During its creation, object C retains object B. What happens to B and C when A is released? Why, nothing, of course. B and C have a cyclic relationship. Releasing object A reduces the reference count of B by one, but B is still referenced by C (and vice-versa) so neither will be deallocated. This isn’t an issue in C++ as the developer manually deletes objects. Deleting A will delete B which will delete C (assuming the destructors tidy things up correctly). Nor is it an issue for C#’s garbage collector because it can tell that the only references to B and C are each other.

For the most part, I’ve used what Objective-C calls “weak references” - I’ve got pointers to objects without retaining them, the same as I would in C++. My code probably looks hideous to experienced Objective-C coders as I’ve trampled conventions all over the place.

One of the main reasons I upgraded to OSX Lion so quickly was the promise of ARC, or “Automatic Reference Counting”. Skimming through the docs suggests that there are a lot of edge cases to it, though (that seems to be a common theme with Objective-C - watch out for the edge cases), so I’m sticking with the traditional method first in order to understand fully what ARC is replacing.

A bug that caught me out for a while was a classic Objective-C memory leak. The “Leaks” utility insisted I’d leaked memory from one class like crazy, but it also told me that the reference count for all leaked objects was 0. That makes no sense until you remember that Objective-C allows you to make boneheaded mistakes like this:

- (void)dealloc { }

Oops. All dealloc methods should call the superclass’ dealloc method:

- (void)dealloc {
    [super dealloc];
}

I’d have suggested that Apple use the template pattern for this instead. NSObject could have methods like this:

- (void)onDealloc { }

- (void)dealloc {
    [self onDealloc];
    [super dealloc];
}

User code would look like this:

- (void)onDealloc {
    // Cleanup here
}

It’s now impossible to leak memory by forgetting to dealloc the superclass. I imagine there’s a valid case for giving developers the power to shoot themselves in the foot, but there’s a lot of boilerplate code needed in classes that could be excised very easily by using the template pattern. The same is true for object initialisation. Here’s what you do now:

- (id)init {
    if ((self = [super init])) {
    // Initialise the object
    }

    return self;
}

This is what a templated NSObject could look like:

- (void)onInit { }

- (id)init {
    if ((self = [super init])) {
        [self onInit];
    }

    return self;
}

This is what a user class would look like:

- (void)onInit {
    // Initialise the object
}

Tidier, but potentially less powerful.

Performance

Running the OSX version of Really Bad Eggs through Xcode’s CPU profiler demonstrates how efficiently the game works. Most of the game code barely registers; cocos2d’s drawing routines use several magnitudes more CPU time than anything else in the game. It also demonstrated how abysmally slow the NSArray objects are. One function I used them in took up more CPU power than anything else in the entire game (except the cocos2d drawing routines), so I refactored the function without NSArrays and the problem disappeared.

Dynanism

The dynamic nature of Objective-C means I’m happy to use calls to an object’s isKindOfClass method, whereas in C++ I’d have been more inclined to refactor to remove the need for type checking or calls to dynamic_cast<>(). For example, the C++ function to test if two eggs can be connected looks like this:

void NormalBlock::connect(const BlockBase* top,
                          const BlockBase* right,
                          const BlockBase* bottom,
                          const BlockBase* left) {
    setConnections(top != NULL && top->getColour() == _colour && top->getState() == BlockBase::BLOCK_STATE_NORMAL,
                   right != NULL && right->getColour() == _colour && right->getState() == BlockBase::BLOCK_STATE_NORMAL,
                   bottom != NULL && bottom->getColour() == _colour && bottom->getState() == BlockBase::BLOCK_STATE_NORMAL,
                   left != NULL && left->getColour() == _colour && left->getState() == BlockBase::BLOCK_STATE_NORMAL);
}

All egg classes inherit from the BlockBase class (descriptive name, I know) which includes a “_colour” member. Each subclass sets this to a colour representative of the bitmaps used to display the egg. The red egg has an RGB value of (31, 0, 0) whilst the blue egg has an RGB value of (0, 0, 31). Checking if two eggs are of the same type simply entails a comparison between two 16-bit integers.

The Objective-C function just compares the eggs’ classes instead:

- (void)connect:(BlockBase*)top right:(BlockBase*)right bottom:(BlockBase*)bottom left:(BlockBase*)left {

    BOOL topSet = top != NULL && [top class] == [self class] && top.state == BlockNormalState;
    BOOL rightSet = right != NULL && [right class] == [self class] && right.state == BlockNormalState;
    BOOL bottomSet = bottom != NULL && [bottom class] == [self class] && bottom.state == BlockNormalState;
    BOOL leftSet = left != NULL && [left class] == [self class] && left.state == BlockNormalState;

    [self setConnectionTop:topSet right:rightSet bottom:bottomSet left:leftSet];
}

It’s not a major change, but it does remove some cruft from the code.

Blocks as Callback Functions

The Grid class represents the well of eggs and manages all of the eggs within it. It includes functions for rotating the live eggs, identifying and exploding chains of eggs, and so on. In the C++/DS version, the Grid class is also responsible for calling methods of the SoundPlayer class to trigger audio playback every time anything sound-worthy occurs. This works, but it’s not terribly clean - the Grid shouldn’t need to deal with sounds. The design ties the logic of the game to the platform it is running on.

A better solution would be to trigger an event, but if you’ve ever implemented an event system you’ll know that it’s a very verbose pattern. At the very least, you’ll need interfaces and classes that represent event arguments and event listeners. I’d like to tidy up the design but I’m not that bothered.

A considerably terser option would be to use a function pointer as a callback method, but that opens up a whole can of non-OO, global namespace-polluting nastiness. C++’s pointers-to-members are so limited - the exact type of the pointed-to object must be known - that they aren’t even worth considering.

Another possibility would be to create a message queue and have the grid push messages into it. A message pump would dispatch messages to the sound player object as necessary. Again, this is ugly and involves far too much new code for virtually no benefit.

It was only after working through this familiar thought process that I remembered that Apple has added closures (“blocks”) as a non-standard extension to C. With closures, the problems disappear. No bloated event system, no global namespace pollution with random C functions, and a simple way to extract the sound triggers from the Grid class.

The “Grid.h” file includes the following typedefs:

typedef void(^GridEvent)(Grid*);
typedef void(^GridBlockEvent)(Grid* grid, BlockBase* block);

I think of the typedefs as being analogous to C#’s delegate signatures. The class itself includes the following members:

GridEvent _onGarbageRowAdded;
GridEvent _onLand;
GridEvent _onGarbageLand;
GridBlockEvent _onBlockAdd;
GridBlockEvent _onBlockRemove;
GridBlockEvent _onGarbageBlockLand;

The class triggers the closures like so:

if (_onBlockLand != nil) _onBlockLand(self);

Wiring up code to an instance of the Grid class is simple:

Grid* grid = [[Grid alloc] initWithHeight:2 playerNumber:0];

grid.onBlockLand = ^(Grid* sender) {
    printf("A block has landed");
};

It looks like C, and it tastes like C, but I can perform JavaScript-like tricks with it. ‘Tis a beautiful abomination.

I’ve used this pattern all over the code to trigger sounds and visual effects as well as add/move/remove sprites. The game engine code is completely separate from the presentation layer.

Classes as Objects

The BlockFactory class has also benefited a little from the switch to Objective-C. When a grid needs to place a new egg, it fetches a new egg instance from the BlockFactory rather than create the egg itself.

The BlockFactory is necessary because all players receive the same sequence of eggs. Suppose player 1 requests his third pair of eggs and is given a red egg and a blue egg. When player 2 requests his third pair of eggs, he must also be given a red egg and a blue egg. No player can “cheat” due to a particularly advantageous sequence of eggs. Winning is a matter of skill and speed rather than luck.

The BlockFactory must, therefore, maintain a list of all egg types that have been generated. It also needs to remember which pair of eggs all players will receive next. Once a pair of eggs has been used by all players it can be removed from the list. Attempts to retrieve a pair of eggs not in the list will cause a new pair of random egg types to be created and appended to the list. The BlockFactory instance is shared across all players.

In the C++ version, the list stores enum values that represent an egg type. When a new egg is requested, the correct constructor is called for that value using a switch() statement. Here’s the code that adds a new item to the list:

BlockFactory::BlockType BlockFactory::getRandomBlockType() const {
    return (BlockFactory::BlockType)(rand() % _blockColourCount);
}

void BlockFactory::addRandomBlock() {
    _blockList.push_back(getRandomBlockType());
}

Here’s the code that creates a new egg from a given type:

BlockBase* BlockFactory::newBlockFromType(BlockFactory::BlockType type) const {
    switch (type) {
        case BLOCK_RED:
            return new RedBlock();
        case BLOCK_PURPLE:
            return new PurpleBlock();
        case BLOCK_YELLOW:
            return new YellowBlock();
        case BLOCK_BLUE:
            return new BlueBlock();
        case BLOCK_GREEN:
            return new GreenBlock();
        case BLOCK_ORANGE:
            return new OrangeBlock();
    }

    // Included to silence compiler warning
    return new RedBlock();
}

The BlockFactory class includes a BlockType enum necessary for this scheme to work.

The Objective-C version dumps the enum and uses a tidier solution. As classes in Objective-C are themselves objects, storing enum values in the list is unnecessary. Instead, the list stores pointers to the class objects. Here’s the code that adds a new item to the list:

- (void)addRandomBlockClass {
    [_blockList addObject:[self randomBlockClass]];
}

- (Class)randomBlockClass {
    int type = rand() % _blockColourCount;

    switch (type) {
        case 0:
            return [RedBlock class];
        case 1:
            return [BlueBlock class];
        case 2:
            return [YellowBlock class];
        case 3:
            return [PurpleBlock class];
        case 4:
            return [GreenBlock class];
        case 5:
            return [OrangeBlock class];
    }

    // Included to silence compiler warning
    return [RedBlock class];
}

Creating a new BlockBase object from the list becomes trivial. A single line of code will create a new BlockBase object from an item in the list:

BlockBase* block = [[[_blockList objectAtIndex:0] alloc] init];

The item in the list is a class, so calling its alloc and init methods gives us a new object automatically.

The difference between the two sets of code is minor, but conceptually it’s a big leap. Objective-C lets me store classes in arrays. I’m pretty certain that the only other language I’ve used that could do anything even remotely like this is JavaScript.

2011-07-27

More Xcode 4.1 Problems

Xcode 4.1 won’t install on my MacBook. At least, it won’t install if I use the installer provided by Apple. It gets about 98% of the way through the installer and tells me that it is “Updating files”, but won’t get any further.

The secret to getting it installed correctly is to:

  • Right-click on the “Install Xcode” program;
  • Click “Show package contents”;
  • Open the “Contents” folder;
  • Open the “Resources” folder
  • Run the “Xcode.mpkg” program.

This will successfully install Xcode with a more familiar installer.

The problem with being an early adopter of OSX software is that you find yourself plagued with problems you only usually experience in Windows and Linux. Avoiding those problems was precisely the reason I dumped them at home and switched to Apple.

2011-07-21

OSX Lion

After the disaster that was Leopard’s release, I decided to wait before getting Lion.

Then I got Lion anyway.

Quirks so far:

  • Xcode 4.1 downloads from the App Store as an installer, which is totally unexpected. Of course, not knowing this a number of people appear to be running their old copy and then complaining when it’s still, well, their old copy. They don’t realise that there’s an “Install Xcode” binary in their Applications folder.

  • Xcode won’t install unless you quit both iTunes and the iTunes helper app (which you can only achieve via the Terminal or the Activity Monitor in Applications/Utilities).

  • When installed for the first time, Xcode 4.1 wouldn’t work. It complained about the iPhone IDE plugin not loading. Reinstalled it and it worked fine.

  • The inverted scrolling system is vile.

  • It’s very grey. Perhaps the designers spent a bit too long in Aberdeen.

  • Downloaded the ~4GB Lion installer on my iMac. Decided to upgrade my MacBook too. Unfortunately, the installer appears to have been deleted by the upgrade process. Thank goodness I enjoy downloading massive files so much! I get to download the update twice!

It’s pretty obvious that Apple’s main focus is their line of laptops. OK, their main focus is iOS, as that’s where they make their money. They do need the Mac as a development platform, though, and within that set of products, laptops are their main focus. A lot of the new features make no sense on my iMac. For example, the new gestures are quite probably wonderful when used on a MacBook Air with a built-in touchpad. With the iMac, my options are to buy a BlueTooth touchpad (which I won’t do, as my mouse is far more accurate and touchpads are unusable as graphics editing devices) or a Magic Mouse (after trying one in an Apple store, I think it would give me crippling, irrevocable carpel-tunnel within minutes). The gestures are, therefore, useless.

Similarly, the full-screen mode is probably great on an 11” or 13” screen. On a 24” screen, most applications look ridiculous.

2010-01-24

Woopsi 0.44 Released

Time for another release:

http://www.sourceforge.net/projects/woopsi

There’s nothing in this release that I haven’t blogged about already, but here’s a quick summary:

  • Unicode (UTF-8) support throughout entire Woopsi system;
  • FileRequester upgraded from bonus folder to main library;
  • Key repeat events;
  • Text in TextBox follows cursor;
  • Dozens of fixes and improvements.

In addition to this, I’ve deleted the old screenshots from the SourceForge page and uploaded a couple of new ones. Hopefully any sites that report the news of the release will use those instead of the shots from version 0.21.

EDIT: Additionally, I’ve released the Xcode/SDL version of 0.44, for anyone out there developing on a Mac and needing a debugger.

2007-10-19

XCode PALib Template

Following on from the previous post about getting PALib and devKitARM set up in OSX, here’s some instructions for creating a PALib template project:

  • Download the PALib XCode Template
  • Unzip the archive
  • Drag the resultant folder to “/Library/Application Support/Apple/Developer Tools/Project Templates”

All done! To create a project using the template:

  • Fire up XCode
  • Choose “File/New Project” from the top menu
  • Select “PAlib” from the template list
  • Click “Next”
  • Choose a project name and a location for the project
  • Click “Finish”

You’ve now created a basic PALib project that will compile (ROMs are put in the “release” folder) and run in an emulator.