Tuesday, April 28, 2009

zlib.h "_deflate", referenced from:

Just added some simple zipping capability which references zlib.h but when trying to build it, there's a set of errors resolving references from the .o (object) files. This is obviously something to do with the linking to the dynamic libraries, but it's a bugger to find out what exactly and how to solve it.

The problem is that you need to alert Xcode to the fact that you want that library loaded. The easiest solution is Project>Edit Active Target, choose the General tab, and press the + button under linked libraries. This allows you to choose from the frameworks and directories appropriate to your chosen Base SDK (see the Build tab to change this).

Of course, guessing that zlib.h and libz.dylib are related is the easy part.

Monday, March 30, 2009

STAssertEquals doesn't work for NSString (or any object for that matter)

STAssertEquals looks like a useful convenience function when you first stumble upon it, but it's not. SenTestCase_Macros.h reveals its dirty secret in the comments:

Generates a failure when a1 is not equal to a2. This test is for C scalars, structs and unions.

So it's fine for ints and so on, but not a simple workaround for the cumbersome-looking string equality test [string isEqualTo:@"hi!"]. Unfortunately, it doesn't warn you that you're using inappropriate arguments; that realisation is a couple of minutes investigation away.

Sunday, March 29, 2009

SenTestingKit "no such file or directory"

When trying to add unit tests to your Xcode project, there's some very useful information on setting up Xcode for unit testing on the Apple site, but one key piece of information is missing - you may need to manually add the SenTestingKit.framework to your project. Otherwise you'll end up with errors such as 'SenTestingKit no such file or directory' when trying to build your test project.

Add the framework from the context menu on the Frameworks icon. SenTestingKit.framework should be in /Developer/Library/Frameworks. Make sure that you only link it to your test target and not your core project, as this can cause you more problems when trying to run the core project.

When running the tests, failing tests are reported in the standard "Errors and Warnings" section of Xcode, just to confuse you...

Actually, since writing the above, I've found a much better overview of unit testing in Xcode which does cover the points I made above.

Monday, March 23, 2009

nested functions are disabled use -fnested-functions to re-enable

You'll get this error for a weird variety of tricky syntax errors - forgetting to close blocks etc. You'll also get it if you try to use Java syntax for iterators rather than Obj-C2.0 syntax. Don't write this:

for (NSString *value : myArray) {

write this instead:

for (NSString *value in myArray) {

EXC_BAD_ACCESS

gdb getting narked and shouting about EXC_BAD_ACCESS is a sign that you've either released something you should have, or you've forgotten to retain something. Unfortunately, the nature of these problems is that they're Heisenbugs - they may not be obvious when you go hunting with the debugger. See Apple's notes for more help.

Thursday, March 19, 2009

getting and setting the string value of an NSTextField

I can't believe what a mess I made of this, when it's so easy:

[textField stringValue] gets the contents of the field.

[textField setString:@"some text"] updates the field.

Of course, there's always Key-Value Coding and Key-Value Observing if you want to make it harder on yourself...

Monday, March 16, 2009

selector element does not have a valid object type

One of the changes Apple made to simplify coding in Objective-C 2.0 for OS X and the iPhone was the addition of a simple enumeration syntax. Previously you would have written something like: 
for (int i; i<[array count]; i++) {
  [[array objectAtIndex: i] doSomething];
}
But now you can write
for (NSString *string in array) {
    [string doSomething];
}

This is much nicer, but there is a gotcha lying in wait: you can only apply fast enumeration for iterating over Objective-C objects, not primitive types, so the following:
for (int i in array) { 
... 
}
gives you the almost meaningful error "selector element does not have a valid object type". Unfortunately, it places the error message after the closing bracket of the body of the loop, so you may spend some time wondering how a bracket can cause that error...

Sunday, March 15, 2009

assignment from distinct Objective-C type

If you want to overwrite the contents of an Objective C object, you might be tempted to do something like the following:

wordarray = [[NSMutableArray alloc] init];
... interesting things here ...
wordarray = [sentence componentsSeparatedByString:@" "];


You'll find that the second line there gets an enigmatic message "warning:assignment from distinct Objective-C type". If you ignore the message and run the code, everything runs fine so what's the problem? Well, you're stamping all over Objective-C's memory allocation and garbage collection, so at some point in the future, when you're least expecting it, your program will crash dramatically. The safe way to refine the contents of an object is by using a setXXXX: message:

[wordarray setArray:[sentence componentsSeparatedByString:@" "]];

Saturday, March 14, 2009

Unable to read symbols for "/System/Library/Frameworks/UIKit.framework/UIKit"

So you've been playing the XCode and wrapping your head round Cocoa and the Interface Builder, and then you make one inconsequential change, and your whole world falls apart: instead of the gloriously lickable application appearing in the iPhone simulator, the simulator launches and then closes, and XCode reports __TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION__. When you open the debugger window, you see a worrying set of messages such as: 

warning: Unable to read symbols for "/System/Library/Frameworks/UIKit.framework/UIKit" (file not found).
warning: Unable to read symbols from "UIKit" (not yet mapped into memory).
warning: Unable to read symbols for "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics" (file not found).
warning: Unable to read symbols from "CoreGraphics" (not yet mapped into memory).

"What the hell did I do? I deleted my frameworks?? How???" may be the thoughts going through your head right now - but don't worry! All that is happening is the the gdb debugger is looking in the wrong place for the iPhoneOS frameworks; it's looking in the MacOS framework directory /System/Library/Frameworks instead of the iPhoneOS directory which would be something like /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/System/Library/Frameworks/CoreGraphics.framewor. Unfortunately, these messages take up most of the space on the default tiny gdb window, so the error that caused gdb to be launched has scrolled off the top of the screen. If you scroll up, you'll find the real error that your minor change caused.

I've not found a clear explanation why gdb is using the wrong path, or how to correct this, but if you're desperate to suppress these messages, you can set up symbolic links to the appropriate frameworks e.g.
sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/System/Library/Frameworks/UIKit.framework/  /System/Library/Frameworks/UIKit.framework 

If anyone knows how to fix gdb's path information, please let me know.