Objective-C
Here are some interesting things I learned today about the differences between java/C# and Objective-C. Also how to play a sound on your iPhone.
Calling Methods
This was the very first thing that jumped out at me when I started using Objective-C. To call a method, you use the following syntax:
[object message:param1 namedParam2:param2 namedParam3:param3];
You can call a property by using a more familiar dot notation though.
[object setProperty:value]; object.property = value;
Those two lines of code are equivalent. Even though the brackets are awkward to me, I really love the fact that it has named parameters. You always read in your code what the heck it is you are passing in. I love this feature. I wish java and C# both had this feature for the readability of the code alone.
[Update: 6/11]
Thanks to Martin for pointing out to me that these are not actually named parameters. The order matters and the parameters help make up the function name. I confirmed this for myself by writing the following two functions.
- (void) play:(id)x withDuration:(id)y withVolume:(id)z { // } - (void) play:(id)x withVolume:(id)z withDuration:(id)y { // }
These are two different methods. They have the names “play:withDuration:withVolume” and “play:withVolume:withDuration”
Garbage Collection
This one is interesting to me. Objective-C supports garbage collection the same as C#. The unfortunate thing is that it is only supported when developing for the Mac. It is not supported on the iPhone. When programming for the iPhone, you have to worry about memory management like you did back in the old days. This means you have to concern yourself with error prone reference counting with methods “release”, “retain”. This has been the cause of many bugs in the past and could cause your app to suddenly quit unexpectedly if you aren’t careful with memory leaks. The confusion usually was around who was responsible for freeing an object. Was it the library or the calling object? Fortunately, Apple has a firm policy on when to free objects. Basically, you free any object you create. You“create”an object using a method whose name begins with “alloc” or “new” or contains “copy”. If you own an object, you are responsible for calling “release” on the object. Do NOT call release on an object you do not own or you will most likely cause very bad things to happen because the object will have been freed before it was supposed to. If you just follow this convention in your own code, you should reduce your chance for this kind of bug.
There are some classes that have convienience methods that return new objects but are not considered created by the calling method. They are not named with “alloc”, “new”, or “copy”. One example is [NSString stringWithFormat]. This returns a newly created string, but it is created as an autoreleased object. Since we don’t control when they are released, it’s good practice to avoid using them unless there’s a good reason.
I know this is going to trip me up since I’ve been using garbage collection in java and C# for for a LONG time.
Class Methods and Instance Methods
- (id) foo {
return foo;
}
+ (id) foo {
return foo;
}
The first thing this c# developer noticed was that little “-” minus sign at the start of the line. In the java and c# worlds, we are used to putting private/protected/public in front of these methods. I assumed that this was probably a private designator. Wrong. This minus sign actually identifies this method as a method that can be used on an instance object. In both java and C#, you do not put anything in front of the method to identify it as an instance method. The “+” plus sign designates a class method. This is similar to “static” in java and C#. When I thought about it a little more, it makes sense. In Objective-C you have an interface file where you declare the public methods.
Object Identifiers
The second thing is (id). id is a built in type in Objective-C. It is the object identifier. It is a pointer to a struct. All objects are of type id. In a similar way every object in C# inherit from “Object”.
[Updated: 6/11]
id is more similar to the “var” keyword in C#. It’s simply a way of using dynamic typing instead of static typing. Thanks Martin.
Properties
You declare your property i the import file as follows:
@property (retain, nonatomic) UILabel* foo;
The retain here is required because the iPhone is not garbage collected. It will give you a warning if you do not put it here. The other attribute nonatomic tells the compiler that it doesn’t need to worry about creating thread safe code for the methods.
There are two different ways to implement the property. We will discuss the verbose way first. When creating a property called “foo”, you need to create two instance methods “foo” and “setFoo”. This is more similar to the java way of handling properties except in java it is “getFoo”.
- (UILabel*) foo {
return foo;
}
- (void) setFoo: (UILabel*) aFoo {
if (aFoo != foo) {
[aFoo retain];
[foo release];
foo = aFoo;
}
}
The other way to implement the property is a shortcut where the compiler implements it for you. It would only work for simple getters and setters but it saves typing when they are boring methods anyway. You simply add the following to the top of your implementation file:
@synthesize foo;
MVC
It seems to me that the MVC architecture is used by default when writing an app for the iPhone. You can write MVC in any platform, but what I’ve noticed is that most developers tend to program based on the first examples they read. One aspect that I haven’t quite figured out is the whole Interface Builder and the whole IBOutlet stuff. IBOutlet is basically just a define, but Interface Builder uses these tags to know what is available to connect things. You can drag connections and events using these tags. I don’t think I fully understand what I’m doing when I’m making the connections. I understand how to make things work, but I guess I don’t understand on an intuitive level yet. Hopefully more experience will give that to me.
Playing a sound
Whenever this button was pressed, I wanted to play a sound. Here is the code I used to do this:
SystemSoundID soundId; NSBundle *mainBundle = [NSBundle mainBundle]; NSString *path = [mainBundle pathForResource:@"filename" ofType:@"wav"]; NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO]; AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundId); AudioServicesPlaySystemSound(soundId);
I have these in different classes but this is the correct sequence. I created a SoundEffect class do do the actual audio work so I don’t have a reference to the audio includes in the main part of my program. This should work, but if not, I followed this good tutorial: http://www.iphonedevcentral.org/tutorials.php?page=ViewTutorial&id=50&uid=57348970. You will need to include the AudioToolbox in your Frameworks in order for this to work.
A few things to point out:
1. While this is somewhat nitpicking from an abstract point of view, in terms of implementation details you don’t call methods on objects in Objective-C, but instead pass messages to them. It may seem nothing but it is a significantly different way of doing things as you can pass a message to an object that doesn’t respond to it, but can’t call a method on an object that doesn’t respond to it which opens up all sorts of powerful features (similar to those found in Ruby or Python).
2. In terms of running code, connections are just instance variables. In terms the seemingly magical connection made between coding and runtime they are quite different to their opposite number: actions. Actions use the standard NSControl methods setTarget: and setAction: (remember Interface Builder is working with actual objects, not representations of them). Connections on the other hand and linking actual objects to a proxy object (your controller). When the NIB is loaded at runtime, this proxy object is replaced with the instance of your controller objects and then the instance variables are hooked up to the actual objects, either via accessor methods if they exist, or directly accessing the variable if they don’t.
3. id is not equivalent to Object. NSObject is equivalent to Object. Saying something is Object or a subclass means that Object has to be one of the superclasses. This is the same with NSObject, but id allows objects that aren’t subclasses of NSObject. In a nutshell, id is dynamic typing, NSObject is static typing. This often helps with compiler warnings. For example:
NSObject *myArray = [NSArray array];
[myArray count];
Would give a warning that NSObject may not respond to the method count, even though NSArray is a subclass of NSObject. However:
id myArray = [NSArray array];
[myArray count];
Would give no warning. The compiler just cares that some object somewhere responds to count and trusts the object to handle the message if it doesn’t (either by discarding it or forwarding it to another object). It also helps get rid of generics or the need for casting (you’ll notice that all collection classes in cocoa use id rather than NSObject).
4. Obviously this doesn’t help on the iPhone, but if you were to ever program for the Mac there is a class in Foundation called NSSound which would simplify your sound code to:
[[NSSound soundNamed:@"filename"] play];
Unfortunately this is one of the many classes that is missing from the iPhone.
Anyway hope this helps
Thanks Martin for taking the time to help me understand these things better! It’s one of the reasons I’m bothering to write these blog entries.