Skip to content

Classes, part 1


Basics

As we wrote in Introduction Objective-C classes, as in other object-oriented programming language, provide the blueprint for creating objects.

Objective-C separates class's description from its internals details. Description is about the public properties and methods of a class and is known as interface. Details defines the code that actually makes properties and methods work and are known as implementation.

In this tutorial we cover the following topics

  • Experiment 1: how to start
    • Excercise 1
  • Experiment 2: properties
    • Excercise 2
  • Experiment 3: global variables
  • Experiment 4: constructor methods
  • Experiment 5: class methods and variables
  • Experiment 6: class-level initialization method
  • Excercise 3


Experiment 1: how to start

  1. Create a new project class_001 as we did in Introduction. You should see autogenerated main.m file with the following content
  2. Select File | New | New... to create a new class Foo with the following steps

    1. Select File | New | New... from main menu
    2. Select type of a new file
    3. Add the name for the class
    4. Select destination folder
    5. Enjoy the result

  3. Practise simple project's files navigation

    1. Find some files related with curently edited file.
    2. Change the file curently beeing edited.
    3. Open Assistant editor to edit more than one file at once.
    4. Again find some related files.
    5. Open more edit panels.

  4. At the end of the previous step you should be able to see all three files: main.m -- main project file, Foo.m -- implementation of Foo class and Foo.h -- definition of Foo class

    As we can see an interface is created with the @interface directive, after which come the class and the superclass name, separated by a colon. It is possible to define protected variables inside of the curly braces just after superclass name, but it is not recommended.

    Simple explanation for this is that instance variables are often treated as implementation details and therefore should be stored in the .m file instead of the interface.

    The @implementation directive is similar to @interface, except we don’t need to include the super class.

  5. Add some variables to the class and create a class instace.

    Next in main.m try to get an access to one of the variables either by

    or

    You cen even try -> operator like

    All options without success as you can compare with the following screen


    We are not surprised that there is no access to private variables. The question is: Is it possible to have a public variables in Objective-C? Well, yes it is, but it is strongly not recommended. You can do this with @public keyword but you shouldn't. Instead properties should be used. Just to satisfy ones curiosity, please take a look into the following example but try not to use this approach.

    Let's focus now on private variables. To get an access to them we need some methods -- this would be a topic of the next step.

    The conclusions from above are as follows

    1. You can simply create private variables (instance variables).
    2. There is no access to private variables other than with the help of methodhs from the class.
    3. You can not simply create public variable. You can do this with use @public keyword but it is strongly not recommended.
  6. Simple methods.



    and test if it works (should work)

    Now there is a time for an explanations.

    1. Methods naming conventions.

      Objective-C methods are designed to protect from any ambiguities. As a result, method names are terrible verbose, but undeniably descriptive. You can follow this pattern with the following rules for naming Objective-C methods:

      1. Don’t abbreviate anything.
      2. Explicitly state parameter names in the method itself.
      3. Be descriptive.
    2. Methods declaration.

      Lines started from sequence of the pattern - (return_type) method_name declares (in .h file) a method called method_name which returns value of type return_type

      General method declaration pattern takes a form

      for method which takes no parameters, and the form

      for method which takes one or more parameters (three in this case). The minus sign prepended to the method marks it as an instance method (opposed to a class method marked with plus sign -- see next section tutu).

    3. Calling methods.

      To invoke a method we place the object and the desired method in square brackets, separated by a space. Arguments are separated from the method name using a colon:

      If there is more than one parameter, it comes after the initial argument, following the same pattern. Each parameter is paired with a label, separated from other arguments by a space, and set off by a colon:

      It’s a lot easier to see the purpose behind the above naming conventions when you approach it from an invocation perspective. They make method calls read more like a human language than a computer one. For example, compare the following method call from Simula-style languages to Objective-C’s version:

    4. Nested method calls

      Nesting method calls is a common pattern in moder programming languages (Java) or libraries (jQuery). It’s a natural way to pass the result of one call to another. An example of this is a two-step proces of instantiation an object

      First, the [Foo alloc] method is called, then the init method is invoked on its return value.

    5. Method overloading
      Objective-C does not support method overloading, so we have to use different method names. The reason for this is that in a dynamically typed language, type information is very often not known until runtime. At runtime, all objects are statically typed as id in Objective-C. Additionally, a core idea in dynamically typed object oriented languages is that we should not care what type an object is as long as it responds to the messages we want to send.

      Luckily there is hope to solve this problem. Remember that the method name includes the method signature keywords (the parameter names that come before the ":"s), so the following are two different methods, even though they both begin with saveToFile:

      (the names of the two methods are saveToFile:valueInt: and saveToFile:valueString:).

    6. Private mehods
      The simplest method to get private methods is to add them to the implementation but not the interface. Actuall private methods we can get with extensions: see Classes, part 2: Extensions

Excercise 1

Add minimum three more instance variables. Add minimum three diferent methods (with differnt number of arguments) to operate on these variables and use them.


More details


Experiment 2: properties

In object-oriented world, an object’s properties let other objects inspect or change this object state. Sometimes, when we are extremely lazy, we do this with public variables. In a well-designed object-oriented code, it shouldn't happen. It shouldn't be possible to directly access the internal state of an object. Instead, accessor methods (so called getters and setters) are used as an abstraction for interacting with the object’s internal data.

The goal of the @property directive is to make it easy to create and configure properties by automatically generating these accessor methods. What is more important, properties behaves like public instance variables.

  1. Change our code to have a form presented in the following snippets



    and run it

    Lines

    are clear for us and shouldn't surprise us. We use well known dot notation to get an access to a public member of the class (or it looks like we exactly do this what is the same thing from our point of view).

    On the other side, lines

    looks strange. There is a call to undefined method setX as well as x and what is more surprising, both calls works. The answer is very simple. The compiler generates a getter and a setter for the x property. The default naming convention is to use the property name as the getter, prefix it with set for the setter, and prefix it with an underscore for the instance variable.

    Say it again: under the hood the compiler (or preprocessor?) generates for us the following changes for every property declared with the @property directive:

    • Introduce instance variable using the property name and underscore prefix as its name. In our case this would be
    • Generates getter using the property name as its name. In our case this would be
    • Generates setter using the property name and set prefix as its name. In our case this would be

    After declaring the property with the @property directive, we can call these methods as if they were included in our class’s interface and implementation files. Properties accessed with dot notation are translated to the above accessor methods behind the scenes, so for example

    code actually calls

  2. The getter= and setter= attributes.

    If we don’t like @property’s default naming conventions, we can change the getter/setter method names with the getter= and setter= attributes. Test the followig code.

  3. We defer explanation of other attributes like nonatomic, strong, weak and copy to the next tutorials. You can find some information here

Excercise 2

The readonly attribute is an easy way to make a property read only. Write a code to test and show how it works.


Experiment 3: global variables

If we declare a variable inside the @implementation section (but outside curly brackets), we are actually creating a global variable, visible everywhere (in every method in our application).

Member variables can only be declared in the @interface section. They are only accessible in the class itself.

In case you are not familiar with extern please read Understanding “extern” keyword in C tutorial.


2017-03-07 11:03:54.629725 class_part1_private_and_global_variables[84984:4919429] 7
2017-03-07 11:03:54.629989 class_part1_private_and_global_variables[84984:4919429] 8
2017-03-07 11:03:54.630013 class_part1_private_and_global_variables[84984:4919429] 0
2017-03-07 11:03:54.630036 class_part1_private_and_global_variables[84984:4919429] 2
2017-03-07 11:03:54.630056 class_part1_private_and_global_variables[84984:4919429] 2
2017-03-07 11:03:54.630075 class_part1_private_and_global_variables[84984:4919429] 2
Program ended with exit code: 0


Experiment 4: constructor methods

There are no constructor methods in Objective-C. Instead, an object is initialized by calling the init method immediately after it’s allocated. This explains why instantiation is always a two-step process: allocate followed by initialize.

init is the default initialization method, but we can also define our own "versions". There’s nothing special about custom initialization methods as they are just normal instance methods, except the method name should always begin with init.

  1. Use code with a default initialization method



    id type used above is a generic type, something like void but it can hold any kind of object.

  2. Use code with our own initialization method

  3. If you want you can even try to use init name instead of initWithRandomXValue

  4. Class-level initialization method -- see next part of this tutorial.


Experiment 5: class methods and variables

Sometimes we need some properties to be common for all instances of a class or need a method which belongs to the class but not to any particular instances. These are very commonly called "static" properties or methods in other programming languages.

Class method declarations look like instance methods, except they are prefixed with a plus sign instead of a minus sign.

Technically there is no such thing as a class-level variable in Objective-C, but we can "emulate" one by declaring a static variable before defining the implementation.

  1. Copy, paste and analyze the following code



    The result should be similar to presented below

    2016-02-18 23:27:57.779 class_001[5134:544764] x=2024 y=0
    2016-02-18 23:27:57.781 class_001[5134:544764] x=186 y=0
    Program ended with exit code: 0


Experiment 6: class-level initialization method

If we have to make some initializations before the first class usage, the initialize method is designed for this.

  1. Copy, paste and analyze the following code



    The result should be similar to presented below

    2016-02-18 15:05:19.941 class_001[4937:519806] x=2143 y=0
    2016-02-18 15:05:19.944 class_001[4937:519806] x=1072 y=0
    Program ended with exit code: 0


Excercise 3

Create a project according to the following rules

  1. Write a class to cipher documents.
  2. You can implement any cipher algorithm -- it's up to you which one you want to implement.
  3. As a document we understand simple strings and files.
  4. For example this class should allow to
    1. read plain text file, cipher it and immediately save;
    2. read encrypted text file and return a decrypted string we can use in our program.