Beginning Objective-C for the C# Guy
So my new language of the year is going to be Objective-C and Cocoa/CocoaTouch. This is actually a new language and a new IDE and a new platform and, well, everything. I’ve decided to document much of what I’m doing along the way. As you know I switched my main platform to Mac last year and have been doing my .Net development in a Virtual Machine. This has been great, working out extremely well, but part of what I wanted the Mac for was to branch out and explore some different ways of writing applications. Studying a new language is a great way to get a different view of how to accomplish programming tasks, and seeing how things are done on other platforms can only increase your skills as an application developer.
So with this post I wanted to go over some basics, compare some things in .Net to Objective-C, and kind of give a quickstart.
Environment Basics
Some housekeeping terminology. XCode is the IDE you use out of the box to develop mac applications. It’s a full-featured IDE that comes installed on your mac. In some senses it’s not nearly as mature as visual studio, and I find myself missing vs and particularly Resharper, however, you also don’t have to pay $2k for your dev tools, so, worth the tradeoff.
Objective-C (ObjC) is the standard language of choice for developing Mac applications. However it’s not the only one. There is support for Java and Ruby in Cocoa and, of course, OSX being a *nix system, you can write programs for it in any language really. But for the purposes of talking about Cocoa/Mac dev, we’re talking mostly about ObjC.
Cocoa (and CocoaTouch) is your Mac development equivalent to the .NET framework basically. It provides a lot of framework base for mac development as well as the stuff that supports GUI hotness. CocoaTouch is Cocoa for iPhone/iPod Touch environments, with some differences in what it has and what is supported.
Objective-C Basic Information
Objective-C is a “strict superset” of C. This means that all valid C code is valid Objective-C code. Objective-C is an OO language. The Objective-C OO is more like SmallTalk OO than the C++ style OO you are used to. In Objective-C you talk to objects with messages rather than calling methods. For instance the Objective-C code:
MyType *myType = [[MyType alloc] init]; [myType myTypeInstanceMethod:10];
Is essentially the equivalent of the following C# code:
MyType myType = new MyType(); myType.myTypeInstanceMethod(10);
So basically the method calls you are used to in C# turn into message passes in the [] brackets.
The interesting thing about the messages is that you can send messages to an object that may not actually handle them. This is a dynamic typing feature borrowed from Smalltalk. You can choose to handle the message, or forward it on, but if you don’t do something with it you will get a runtime, not compile error. (xcode will give you a compile warning though to protect you from yourself a little.)
Some structural differences that might trip you up: if you have ever done any c/c++ you will be familiar with the practice of separating declaration from implementation on classes and methods and such. This is a luxury that is easy to overlook in C#, where you don’t have to do that. So in Objective-C you have to do that, but the thing you may trip up on is that the declaration of a class is called an “interface”. This is different from what you think of as an interface in C#. In Objective-C the “interface” is the signature of the class being implemented. If you want a C#-style interface that let’s you do composition over inheritance, you are looking for a “protocol” in Objective-C.
Declaring and Implementing a class in Objective-C:
@interface MyObject{ } -(void) myTypeInstanceMethod:(int) integerMethodParam; @end @implementation MyObject -(void) myTypeInstanceMethod:(int)integerMethodParam { //do stuff }
Another thing you may be noticing looking at the code above is the slightly odd method signature. Let’s break it down. The – (minus) means “instance method”. A + would mean class method. Class methods in Objective-C are like statics in c# but they’re inheritance-friendly and can be overridden. (void) is your return type, just like C# but with parens. Then there’s the method name, then after the colon you have the parameters. You add more parameters by adding more colons:
-(void) myTypeInstanceMethodWith3Params:(int) integerParam1:(int)integerParam2:(int)integerParam3
One thing you aren’t noticing is a visibility modifier. As far as I can tell, there’s no such thing as a private class method. You can do some tricks to hide it from the compiler, but because the class methods are really just there to respond to messages the object receives, if you send a message called the same thing as a class method it will get handled.
Unit Tests
If you’re at all like me, hooking up tests is pretty second nature for you in c# now. Being able to write tests to verify my code helps me learn new things in new languages. The testing story is interesting in xcode, especially if you are used to any of the standard test runners and frameworks in .net.
XCode 3.1 comes bundled with a unit testing framework called OCUnit. OCUnit was a third-party open-source project that Apple got behind and took over responsibility for. (wait you mean the vendor doesn’t *have* to write their own test framework?) The mechanics of testing in xcode are a bit obtuse at first. I went here to figure out how to actually set up a testing system, and being totally new to the environment, it took me a while. But follow the steps and you’ll get there.
One thing to note is that there is no concept of a “test runner” like you have with tdd.net or resharper or mstest. In XCode, to do tests, you set up a new build target that understands that it will be running tests. Then tests run as part of your build. That’s it. You build, it runs tests. All of them as far as I can tell. If a test fails, you get a build error. At first this feels like a much lamer experience than say the R# test runner, but on the positive side there’s no skipping tests and you do get the error inline with the code window. Either way, it takes some getting used to. As a side note, my homesickness for R# really kicks in as my “tdd workflow” in ObjC is clunky and very slow right now.
Your tests in OCUnit are a convention-based thing, unlike a metadata (attribute) thing in .net. Your test methods must be void and must start with “test”. You also get a setup and teardown. This is a test fixture I wrote for doing the first Project Euler problem. It’s not really my typical style (I haven’t bothered trying to get a BDD flow going yet) but it shows the basics:
@implementation eulerproblemonespecs EulerProblemOne *newProblemOne; -(void) setUp { newProblemOne = [[EulerProblemOne alloc]init]; } -(void)tearDown { [newProblemOne release]; } -(void) testItShouldFindMultiplesOfThreeAndFive { //doing it with a variable bool isMultiple = [newProblemOne isMultipleOfThreeOrFive: 4]; STAssertFalse(isMultiple,nil); //passing the message inline STAssertTrue([newProblemOne isMultipleOfThreeOrFive:3],nil); STAssertTrue([newProblemOne isMultipleOfThreeOrFive:5],nil); STAssertFalse([newProblemOne isMultipleOfThreeOrFive:23],nil); } -(void)testItShouldSumMultiplesOfThreeAndFiveInARange { STAssertEquals([newProblemOne sumMultiplesInRange:0:10],23,nil); } @end
No other ceremony required other than the naming. In the declaration of the test fixture you just inherit from SenTestCase and go.
So, to close this one out, I’m having a lot of fun learning this new environment. And it is interesting to care about memory management and performance again (very important for iPhone dev). And it’s interesting to think about OO in a different way. If you haven’t chosen a new language for the year, and you have the ability to try it, I’d say give ObjC/Cocoa a shot. Now is as good a time as any to learn Mac/iPhone dev, market share is going up and the AppStore is kicking. Plus maybe you’ll learn a little something from a development community that values user experience at a very high level which, let’s face it, is not a priority in the Microsoft ecosystem. Trying new things and delving into new communities can only be good for your career in a down economy as well, so what are you waiting for?