Now how about a struct for a dog? We could do this.
However, there’s duplication of code. If we want to add something to the Pet struct we would have to remember to change it in the Dog struct, too. This is a bad programming practice.
Here’s a better way.
That’s right, we can use one of our own structs as a variable in a new struct. How do we program with it?
Hmm, that looks a little clumsy and complicated. And what if we have even more nested structs? It would just continue to get more and more messy and complicated. There must be a better way.
Object-Orientation for the Win!
Object-Orientation gives us a much better way to share data and code. Let’s redo the structs written above in Objective-C classes. First the Pet class in the Pet.h file.
And the Pet.m file.
With a small amount of code we are able to hold the same data as our previous struct. However, we also have a lot more.
The class is in its own files that we can move to other projects.
We have getters and setters automatically generated for us.
We have a place to add methods that work exclusively with our class.
And we can subclass our class. Um, what?
If we have a class that has all the basic data for something, like our Pet class, it would be great if we could just use it and data for our Dog without duplication and with minimal complexity.
And we can! It’s called subclassing.
Here’s our new Dog class. Dog.h is first.
This line is the key.
With that one line we are now a Dog and an Pet. A Pet, too? In what way?
An instance of Dog has the same properties as a Pet. Here’s how it works.
First, let’s make a pet instance.
But, we don’t know what kind of pet this is! Actually, it doesn’t really make any sense to create a Pet instance since there aren’t any pets that are just Pets.
Subclassing! Our Dog class is a subclass of Pet. That means we can do this.
All the properties that Pet has, Dog has too. That’s convenient.
That’s neat what’s the point you say?
We can also add stuff to the Dog class.
We still have all the data from the Pet class. We inherited it. We also have our own data just for this kind of Pet.
This is the simple basics of Inheritance in Object-Orientation. There’s a lot more to, but this is a good start.
The next piece of Object-Orientation we’re going to learn is method overriding.
Here’s the setup. What if the Pet class had a method that did something for a generic pet. And then we wanted to do something different. Could we do that?
Sure can, let’s start by adding a method to the Pet class. First in the Pet.h file right after the properties.
We put this in the Pet.m file.
This is how we use it with the two objects we have.
Well, that’s boring. I want to customize the one for Dog. No problem! Just implement the method again in the Dog.m file.
The full Dog.m file just so it’s clear.
That’s right, we just rewrote the same method in the Dog.m file. Notice that we didn’t have to add the declaration in the Dog.h file. The declaration is already in the Pet.h and we inherit it.
We overrode the method. When you send the exercisePet message to a Pet instance, it runs the code in the Pet.m. When you send the same message to a Dog instance, it runs the code in the Dog.m file. Easy!
One more thing. What if we want to run the code from both of the .m files? So, when we send the exercisePet message to a Dog, we want the code in the Pet.m file AND the code in the Dog.m file to run. How do we do that? With the new Objective-C keyword super.
Here’s the modified method in the Dog.m file.
Line 4 causes the code from the superclass to run first. Superclass?
The Dog class is called a subclass and the Pet class is called the superclass.
The super keyword is similar to the self keyword. self lets us send messages to other methods in the same class. With super we can send messages to the methods in a superclass.
Now, with one line we get the following output.
All objects inherit directly or indirectly from NSObject
NSObject has an instance variable called the isa pointer. The isa pointer points to the class that created it.
When sending a message to an object, the search follows the isa pointer to look for the method in the object’s class. If the method is not found then it starts looking in the superclass. The search stops when either the method is found or the top of the hierarchy is reached (NSObject).
description and %@
You have been using %@ so that an object can describe itself. The %@ sends a description message to the object being pointed to.
The description method returns a NSString that is useful for describing the instance of a class.
description is an NSObject method so every object has one. However, this implementation returns the memory address of the object as a string (which may or may not be that useful to you).
You can override the default implementation of the description method.