PrEV
Thoughts from a NeXTStep Guy on Cocoa Development

All The C You Need to Know?

Jan 08, 2013 by Bill Dudney

It has been 10 and half months since I posted this question to everyone. It took a lot longer than I expected it to but I've finally shipped the result of your kind comments. You can find All the C You Need to Know in living color on your iPad here.

The current version is envisioned to be an iPad only book. I have had several requests to make it a PDF but I don't think the interactive content works as well in that format. So for now you'll have to file a bug with Apple to try and get iBooks on your Mac if you want to read it off your iPad.

Permalink     10 Comments - Add Yours

iVars vs Properties

Mar 11, 2009 by Bill Dudney

While going over some of the errata on the book Chris, Daniel and I spent a bit of time talking about using '_'s in instance variables. It struck me during our conversation that I have not really seen much discussion on naming ivars vs naming properties. I figured I'd blog about it and get your thoughts.

This is how I am currently leaning because it clearly helps me keep in mind the ivar vs the property.

@interface Foo : NSObject {
    NSString *_gak;
}

@property (copy) NSString *gak;

- (void)doSomething;

@end

What I don't like about this is that if I have an ivar that I want to make an outlet in IB (with IBOutlet) then I have an _ on the outlet name in IB. As Ashley points out in the comments though the current recommendation is to have a property for your outlets. Mostly I like that, but I'd also prefer sometimes that getting to an outlet be more difficult than calling a get method. As Brendan points out (also in the comments) though if you have a property you should place the IBOutlet tag on the property rather than the ivar. Semantically they are the same, practically though if you have your ivar and property named differently the ivar's name will show up in IB, which might not be what you want.

In the implementation I do this;

@synthesize gak = _gak;

- (void)doSomething {
  NSLog(@"gak = %@", self.gak);
}

That keeps things nice and clean, I'm always using the get and set methods via the dot notation.

Thoughts? What do you do?

Permalink     14 Comments - Add Yours

IB, the ultimate inversion of control container...

Jun 18, 2008 by Bill Dudney

In the Enterprise Java world IoC containers are all the rage as popularized by the wildly successful Spring Framework.

It struck me this morning while trying to explain how IB works that IB & AppKit work together and make something a lot like an IoC container for interfaces. This is probably old hat and has been discussed at length in the past. What really struck home though is that in 1989/1990 I was doing IoC on a NeXT cube.

So elegant and before its time... I'm really glad its time has finally come.

Permalink     Add A Comment

Unit Testing with Xcode 3.0

Dec 29, 2007 by Bill Dudney

Coming from the Java world after a long absence from the Cocoa/ObjC world had gotten me hooked on unit testing. So over the last year or so as I've built various Cocoa applications I've always felt a bit out of place without some sort of automated developer tests. I have built a few but the SenTestKit was always such a pain to setup and stuff that I've not been very diligent.

Recently I've been developing a physics engine (a really simple one) for a simple game I'm writing. Well 3D geometry and physics simulation is not something I feel comfortable with building without some sort of automated developer tests to make sure I'm not hosing stuff as I go along and add features and fix bugs. So I have gotten serious about making unit testing work. While I still don't have all the details figured out I do have something working and I thought I'd share what I have on my blog so that I will always have a place to come back to when I forget the rather long and complex path to getting unit tests setup. And yes I have filed bugs for both the complexity and the lack of docs.

And no I won't try to sell you on the virtues of unit testing. It has worked well for me for years in the Java world and generally it just makes sense to me that I should use software to take care of boring repetitive tasks for me.

A quick procedural note, I refer to the images frequently in the text. They are grouped, so when you click on any one in the group you can move between them with next and previous buttons. The idea is that you can read the text then click on the images to follow along on your app.

A real quick and dirty intro to unit testing ObjC. The SenTest project started as an open source JUnit contemporary for testing ObjC. Apple liked it so much they added support for it to Xcode and eventually assumed responsibility for the whole project. The basic idea behind SenTest is that you write your tests just as you would any other code, they live in the project they test. The test code however is not part of the actual code base, instead the tests are compiled into a bundle that can be loaded dynamically if requested. That way our tests can live next to the code they test but won't go out with the release build of our apps.

I have created a really simple example app for you to grab if you want to see the finished product. The project is available here.

Before we get started lets do a quick list of steps.

  • Create a new Target for our unit tests to live in.
  • Configure Application Executable for Test Bundle Injection.
  • Configure the Test Bundle for injection.
  • Configure GDB to run the app internally.
  • Add tests to your Test Bundle.
  • Run and debug the tests.
  • Live Happily Ever After.

Create a New Target

So lets get started making tests. First step is to add a new target. This new target is responsible for creating the unit test bundle that will be loaded dynamically when the tests are run. The image group walks you through these steps. You should control click (or right click) on the Target group and select Add->New Target... In the wizard that pops up choose Cocoa->Unit Test Bundle (be careful to choose Cocoa instead of Carbon) then click next. Name the target (I named it UnitTests and will refer to it like that in the rest of the tutorial) and click finish.

And the final step is to add the application as a direct dependency of our unit test bundle. That will make sure the app is built even when we have our unit test bundle set as the active target.

Step 1

Configure Application for Test Bundle Injection

Recall that our test bundle must be injected into our app at run time to get the tests to run (we could set up an alternate executable to run the tests but this way they will be built all the time instead of when we think about doing it). The first step to doing that is to open the inspector for your executable. Choose the executable and right click and choose Get Info or use Command-I. Next we want to add the arguments and environment variables that will cause our tests to be run. First add the argument '-SenTest All'. That causes all our tests to be run, we can also specify specific individual tests to by specifying the test class name or the test class name followed by '/' and the method name, like this MyTestClass or MyTestClass/testIt.

Next we need to specify which bundle to dynamically load, that would be our UnitTests.octest bundle. When we used the wizard to add our testing bundle it setup the extension to 'octest' for us. So all we have to do here is specify it. We add an environment variable called XCInjectBundle and make its value UnitTests.octest (or whatever you named your test bundle).

Next we specify the injection bundle called DevToolsBundleInjection.framework. We do this via the DYLD_INSERT_LIBRARIES environment variable to $(DEVELOPER_LIBRARY_DIR)/PrivateFrameworks/DevToolsBundleInjection.framework/DevToolsBundleInjection. This is a flag used by the dynamic linker. When set (as a colon separated list of libraries) it tells the linker to load these libraries before any referred to by the program that is being loaded. This framework will take care of performing the injection of our test bundle for us.

And finally we set the DYLD_FALLBACK_FRAMEWORK_PATH to $(DEVELOPER_LIBRARY_DIR)/Frameworks so that the linker can find the SenTestingKit framework. This is part of the process that I don't fully understand. From reading the docs it looks like this gives the linker clues about where to find libraries that are not in their installed directory. The SenTestingKit.framework is compiled as a relative framework with the @rpath as its initial root directory. This flag apparently tells the dynamic linker where to look for @rpath stuff. If anyone has any better insight into this please comment so I can clean this paragraph up. Thanks!

Step 1

Configure Test Bundle for Injection

For loading the bundle we need to set up the BUNDLE_LOADER and TEST_HOST build properties for the tests bundle. Recall that our application is going to be the bundle loader so we just need to specify the application executable as the BUNDLE_LOADER. Select the unit testing target and open the inspector (Comman-I, or right click Get Info) and then choose the Build properties tab. Then type bundle into the search field. Double click on the Bundle Loader field and set its value to $(BUILT_PRODUCTS_DIR)/YourAppName.app/Contents/MacOS/YourAppName. Then go back to the build properties list and double click on Test Host and set its value to $(BUNDLE_LOADER). These two build flags tell the test machinery the place that the testing bundle should be injected.

Step 1

Add Tests to the Test Bundle

And finally we can add a test. I usually add a Test group so I can organize my tests but it won't matter if you do that or not for the tests. Right click on the group you want to add the test to then choose Add->New File... When the wizard comes up choose Cocoa->Objective-C test case class and hit the Next button. Then name the test whatever you'd like. Make sure to set its target to the unit testing bundle instead of the default of your app.

Step 1

Add Code to the Tests

Now lets write a test. In this code we are doing nothing special, the setUp method creates the object we are going to test and the testAdd test to make sure 4 plus 5 really does come put to 9. Any method that starts with 'test' will get executed.

- (void)setUp {

    // create the object(s) that we want to test

    [super setUp]

    testable = [[Testable alloc] init];

}


-(void)tearDown {

    // clean up any stuff like open files or whatever

    [testable release];

    [super tearDown];

}


- (void)testAdd {

    STAssertEquals([testable add4:5], (NSUInteger)9, @"should add 4");

}

Configure GDB

And finally one last thing. You need gdb to run the exe internally instead of launching a separate shell. To do that edit the file ~/.gdbinit and add set start-with-shell 0 to the file.

Now switch the active target to you unit testing bundle and hit build and go. If everything is setup correctly your app should come up and the test (that we have not written yet) executed and then your app should shutdown.

Run and Debug the Tests

And finally we can also debug our tests. Set a breakpoint in a test (say one that is failing) and then you can step though the code and figure out what is wrong. Sure beats log statements :) The trick is to use the debugger directly instead of using Build and Go. Use Alt-Command-Y or just hit the Go button from the console.

Step 1

And there we go, debugable unit tests in our Cocoa apps!

This tutorial tries to be exhaustive and show you ever single step to getting going. If you follow along with your own code and something does not work, please let me know so I can fix it. Hope you enjoyed it and that it helps you get your code tested.

And finally much thanks to Chris Hanson without whose blog entries and help on the Xcode users list I'd have never figured this out.

Permalink     12 Comments - Add Yours

Book Status

Oct 02, 2007 by Bill Dudney

The Debugging chapter is almost done. We are getting near the point where we need reviewers. If you are interested in helping make the book better and learning ObjC in the process (hopefully an way :) the please email me or leave a comment.

Permalink     4 Comments - Add Yours

Writing Perfect Code?

Sep 17, 2007 by Bill Dudney

I've just started writing the debugging chapter of the Objective C book and I'm thinking about many conversation I've had with many programmers over the years. Is it possible to write perfect code? Most programmers when asked that question scoff and say 'duh, there is no way'. But our behavior says differently. In other words, most people would say that they can't write perfect code. But when they code they act as if they can.

I think the base of this issue is the difference between intellectual assent and belief. Intellectually most folks would agree that they are not capable of doing much of anything perfectly. They know instinctively that they have written bad code in the past and are likely to do so in the future. However many people code as if they won't mess up or worse (IMO) that no one that uses their code will mess up. An example to illustrate my thinking...

For example you have probably seen something like this error message if you've had a chance to play with CoreData;

exception: Cannot perform operation since entity with name '(null)' cannot be found (when saving file).'

As a developer using CoreData and ObjectControllers would you rather see this error message while your app is running or would you rather see the thing fail on loading the busted nib? The underlying problem is that the entity name was not set in the nib file for the array controller. Simple to fix and easy to understand from this error message if you'd been hit in the head with it once. If you've not had to solve this issue before though its not so obvious what the underlying problem is. Why is the entity name null, is my model messed up? Aw man I was just editing that and I though it was fine. Break out GDB and starting trying to track down the problem....

For me death on loading from the NIB would be preferable to sometime during the execution of the program. As a developer I'm a lot more likely to find and fix errors if I can find them quickly. If the controller would simply die when the entity name is not set I'd know about the error early instead of late. The controller has all it needs to know it won't be able to do what it should. I could easily die an early death on awakeFromNib (you specify the mode of the controller in IB, set it to Entity or Class). So why not do that?

This is by no means an attempt to pick on the CoreData folks or the AppKit folks or anyone for that matter, its just an example of something that happens to all of us. I'm no exception here. I have to constantly remind myself that my code is not perfect, and I better code that way.

So how do we make it better? There are a few tricks that I'll talk about here but more or less these ideas just common sense;

  • Code for the developer not the machine.
  • Clever is sometimes required but most of the time its not.
    • Clever leads to difficult to find problems.
  • Test everything, automate what you can.
  • Invest in decent error messages.

Code for the developer, not the machine: Developers have to read your code (and if you are a one person show you have to read it, sometimes months after you wrote it) and maintain the code. The ease of use inherent in your code is a result of good API and good error messages. We should write methods that can easily be understood from their names. And the code should be defensive, it should expect that all the code that calls it will forget to do something that is required. If you code (esp in debug mode) asserts its assumptions and those assumptions are violated you will know a lot sooner than the memory access exception. When I code I try to think, what does this method expect to be true, and what can I do to make sure that those things are true. This might slow you down a bit in the beginning but as you start to build on the small 'bullet proof' parts of the code you will be much more productive because you won't be dorking around with finding bugs in your assumptions.

Clever: Almost all 'clever' code I've every written or used has ended up being a liability to the project. There are a few exceptions but very very few. By clever I mean code that uses tricks or side effects to accomplish the goal. Sure the code might do something amazing. But in the long run that code will weigh you down. It will cause unforeseen problems and restrictions with every upgrade etc etc.

Testing is key. If you test your code you will know if it works at least how it fails and thus how to fix it. I have recently come from the Java space so spent a lot of quality time with JUnit and TestNG. I'm a big fan of unit testing despite what Wil Shipley said here I've seen unit testing save many a team's back side during refactoring/reworking of code. Wil ends up posting some great comments in the responses to his blog entry BTW, if you have a spare 10 or 15 minutes to read through there is tons of valuable stuff there from many view points. In addition to some pretty funny responses from Wil about drones etc. Its a good read. But back to the subject at hand. What ever you do make sure to test, be it integration tests where you are pretending to be a user, unit testing or anywhere in between. What I have found especially useful is to write tests for bug reports. That way I have an automated way to make sure the bug does not come back.

Finally on testing, automate everything you can. If you can exercise your code with OCUnit tests then do so, if you do gui testing then do you best to automate as much of that as you can.

As a side note I find that most of my bug related tests end up being writing around clever code or my use of it...

And finally thought that inspired this post... Write decent error messages. If you take the time to put an assert into your code please put a decent error message in there. I've seen stuff like 'dood it didn't work' on the console. And while that is clever and punchy and all its not very helpful. Take the extra 30 seconds to say what you mean so that when you or someone using your code violates the assertion they can fix the problem quickly.

Permalink     1 Comment - Add Yours

Book Progress Report

Sep 07, 2007 by Bill Dudney

Well I think I'm close to getting the first chapter done.

Its always tough to get the first chapter done. There is so much more than the outline to the chapter that is being written in that first chapter...

The hardest part for me is always finding the voice, or maybe the real challenge is not finding the voice but getting it right. As I have posted many times in the past (mostly while writing one my of my java related books, some of my thoughts on that are here) everyone learns differently. When I write a book I want to cast as wide a net as possible so that I can teach as many folks as possible. But I also want the book to be focused enough to make sense to someone. So getting that voice right can be a real challenge.

When writing a blog its so much easier because each entry can be focused on one learning type, other learning types will be hit in another entry after all.

With the help of my editor Daniel Steinberg I think I've finally found the voice of the book. Basically I'm aiming at folks coming from other languages. Cause most of the folks coming to the mac seem to be coming from somewhere else. What that means is I don't have to spend a lot of time talking about what a for loop is and that kind of stuff but instead I can focus on in Java you do 'foo' in ObjC you can do something similar but you do it like 'bar'. I think this will end up with a book that is readable for folks new to ObjC even if its their first language.

Who wants to read a 3 page description of the for loop anyway ;)

Well with all that said I'd love to get your thoughts and commentary on what makes a great book.

Permalink     4 Comments - Add Yours

To delve into for or not to delve...

Aug 20, 2007 by Bill Dudney

Well I've finally got my signed contract in hand and I've submitted the first bits to the publisher (still not a complete chapter yet). The momentum is building and I'm sure I'll have that first chapter cranked out this week. In the mean time I would like to ask readers (all 3 of you) what you would like to see in an ObjC book. I have a plan and I'm executing against it but I'd still like to hear what you'd like to see.

Are you someone that is currently doing C/C++/C# on Windows or someone that is currently doing Java and wants a translation guide. If so the book could contain examples like 'you do this in C# but in ObjC you do this'. I like this approach as a reader because I don't have to wade through the introductory material. As an author I don't like it because I'm always afraid that I'll confuse someone new to programming by not explaining the concepts at hand.

I also have thought about the reader that is new to programming, perhaps not totally new but has been doing PHP or Perl or whatever and is now wanting to get into ObjC. That book would have things like 'this is object oriented concept A and its important because...'. Again its sort of a translation guide from languages that are not as object oriented and therefore the reader has more conceptual ground to cover but as the author I can still assume a knowledge of looping constructs. The down side is that the book would miss the mark for those experienced in object oriented languages.

Finally the book could take the approach of describing ObjC and not making assumptions about the background of the reader, except for rudimentary assumptions like familiarity with a computer. In many ways I like this approach (as the author) because I can fully explain where I'm coming from on any given topic and not make assumptions. The thing I don't like as a reader of these types of books is that I already know programming language 'X' and I don't really need a fundamental discussion of looping constructs.

So I have a plan and I'm running with it but I'd love to have your thoughts and insights on what would make a good ObjC book for you

Permalink     2 Comments - Add Yours

ObjC 2.0 Book!

Aug 09, 2007 by Bill Dudney

While the wait for Leopard is killing me (I can't blog about it or I'll get smacked) I figured I'd post that I got a book contract with The Pragmatic Programmers. I can't begin to tell you how excited I am to be writing for them, and to be writing about ObjC 2.0. Its going to be fun!

Sam Griffith is my co-author. He and I have been friends since 1993 while building NeXT apps for Pan Canadian up in the great white north. Sam is also the co-host of The Stack Trace. A pod-cast devoted to the fine art of software development.

We are both very excited about the chance to do this project. Permalink     Add A Comment