How to send messages (aka call methods) in Objective-C

This is Part 3 in a three-part series on Methods in Objective-C. If you want to learn more, check out the others:

  1. How to read (and write!) method declarations in Objective-C
  2. How to implement methods in Objective-C
  3. How to send messages (aka call methods) in Objective-C

OK, so you know how to declare methods and how to implement them, as well as where to put those declarations and implementations. But if you want to actually have your methods do something, you need to know how to call them. Or, as we say in Objective-C, you need to know how to send messages to objects. (If the “sending messages” concept is hard to grasp, just think of it as calling methods for now.) So how do we do it? How do we get our objects to do stuff?

Well, we just send messages to them. For example:

[carController driveCar];

So here, we’re telling our carController object to go ahead and drive the car. Or, in Objective-C speak, we’re sending the driveCar message to the carController object. And that carController reference on the left is called the receiver. Which makes sense, since it’s receiving the message.

In Objective-C, we send messages with square brackets and spaces. This is roughly equivalent to carController.driveCar(); in Java. So the space replaces the dot, the paretheses are gone, and square brackets surround the whole thing.

Oh, and that carController object is presumably an instance of our CarController class. Let’s look at the line that should precede the one above – where we create that instance:

CarController *carController = [[CarController alloc] init];

Ah, yes, so carController is an instance of CarController. Whew. But wait, what’s going on here? It’s an assignment, but double square brackets? What’s happening?

Well…let’s start from the left. We’re creating a pointer to an instance of CarController called carController. And then… those double square brackets… Let’s break them apart and start from the inside. First:

[CarController alloc]

OK, so we’re sending the alloc message to the CarController class. The alloc method is a class-level method that’s defined on NSObject, and that’s how we get a new instance of our class. It just allocates the memory for our object. We then immediately send the init message to that new instance:

[[CarController alloc] init];

Like alloc, the init method comes from NSObject, and in init, the class is initialized (as you probably guessed). We can override init if we’d like to perform any custom initialization of our newly allocated object. In our CarController, we might want to override init and create a new car inside of it so we’re ready to drive when we receive the driveCar message. We certainly wouldn’t want to leave our caller waiting on us to build a car every time they ask us to drive! Or, actually…we could just make them give us a car in the driveCar: method:

- (void)driveCar:(Car *)car;

(We saw this method declaration earlier in our CarController interface.) If we’re going to call this method, we’ll need an instance of our CarController and a Car. So…

Car *car = [[Car alloc] init];

There’s our car. We saw all of this before when we instantiated a CarController. So you remember that we’re sending the alloc method to the Car class and then sending init to the instance, right? This would be a good time to note that you’ll always see an init like this immediately following an alloc message, as it’s a requirement. From the docs: “You must use an init... method to complete the initialization process.”

Alright, so since we have our car, what’s next? How about an instance of our CarController? (You’ve seen this before.)

CarController *carController = [[CarController alloc] init];

And now that we have our car and our carController, we can ask our carController to drive that car:

[carController driveCar:car];

Now this is new. We haven’t seen how to pass an argument into a method. But it looks a lot like our previous no-argument call to driveCar. This time, we just have a semicolon to say “hey, an argument is coming!” And then, of course, the argument. No sweat.

But… what if you have a method that takes two parameters like the driveCar:withPerson: method we declared previously? Let’s look at the declaration again:

- (void)driveCar:(Car *)car withPerson:(Person *)person;

How would you call this? Can you guess? Assuming we have an instance of our CarController, Car, and Person, it might look something like this:

[carController driveCar:car withPerson:person];

So we’ve seen a lot of this before, but… We’re sending the driveCar:withPerson: message to our carController object. For the first argument, we’re sending car, and for the second argument, we’re sending person.

Now let’s see all of it together:

// instantiate our objects
CarController *carController = [[CarController alloc] init];
Car *car = [[Car alloc] init];
Person *person = [[Person alloc] init];

// send a message with no arguments
[carController driveCar];

// send a message with one argument
[carController driveCar:car];

// send a message with two arguments
[carController driveCar:car withPerson:person];

And that’s a wrap! If you read parts one and two, you can now:

  1. declare methods
  2. implement methods and put them where they belong – in classes
  3. send messages to objects (aka call methods) and assign variables

That pretty much gives you the ability to do whatever you want in Objective-C. If you can create classes and have them talk to each other, declare and implement methods and assign variables, you can do anything. :)

(Pssst… you might also want to learn about types since, you know, you’ll probably need to use primitives like BOOL, NSInteger, and CGFloat at some point. Oh, and go learn about Foundation objects, too. There’s no reason to define your own string, array, and dictionary classes – even though you probably could now.)

Want to learn Swift, too? Drop your name & email in the boxes below to get the 5-Part Guide to Getting Started with Swift.