xcode

Using Forward Declaration In Your Objective-C Projects

| 4 Comments

Screen Shot 2013-08-08 at 16.56.23

If you’re new to Objective C and iOS development, this topic will explain some important things about Forward Declaration and will help you understand the concept behind it.

So, let’s skip the theory and jump right into a small example to see what it’s all about.

We’ll create a small project, that is quite useless, but will at the same time serve as a good example and cmake utility.

So, here is…

Empty class Warrior

Empty class Armor

main.m as a driver – it just creates Warrior object and prints it

And cmake configuration file

So, let’s build our simple program

We see which modules are being built

And now we’ll add an ability to wear armor

Remember this state, we’ll get back to it later.

We need to inform compiler about the Armor class in order to compile these changes.

The first approach is to use #include/#import statements and it’s being used by a lot of developers.

So let’s do it

and build

Looks good, but let’s add some property to our instance of Armor class, e.g. ‘is it magical?’

and let’s build our program again

Good news is that the build of main.m was successful. There’s one thing though. Despite of the fact that the build has been successful, workflow has not been optimal – main doesn’t use Armor, therefore, it must know nothing about this class.

Ok, let’s get back to the state where we’ve added wearArmor: method, but haven’t included Armor yet.

Now we’ll go another way:

Use #import at implementation (Warrior.m) and forward declaration (@class Armor;) at header (Warrior.h)

Make it (make sure that you’ve removed isMagical from Armor, we need this to get the same experience as before)

Add isMagical method again

Build and check the results

Now it looks much better. Did you notice an important difference?

In our example we have only three modules, so the benefit is barely noticeable.

Things change dramatically when you’re working on a large project consisting of numerous classes and modules with lots of dependencies and complex relationships. Every time you add some small thing into the project you’ll have to wait more and more for compiler to re-build all the things. This is where you can get the full benefit from utilising FD approach.

You can experience exactly the same problems when using @protocols as delegates.

So the right way is to use different files for a delegate and a class, which use this a delegate:

To summarise, keep in mind the importance of forward declaration, as it might save your time dramatically with every build you run for the project.

In short, your goal is to create as clean interface as possible, that would be readable and maintainable by others in the future. Therefore, it must contain only imports of a base class and protocols, which current class conforms to. For all the rest there’s… no, not MasterCard, forward declaration in this case.

Share
* Railsware is a premium software development consulting company, focused on delivering great web and mobile applications. Learn more about us.
  • Stanislaw Pankevich

    Спасибо, очень интересно. Я когда-то интуитивно перенял эту практику с одного проекта на Github, но теперь после этого поста, можно сказать, познакомился с ней официально, “прямым текстом”.

    • Alex Denisov

      You’re welcome!
      Рад, что кому-то пригодилось :)

      • AlexThumb

        Alex, спасибо за статью!
        Как я понимаю ускорение условное , так как мы просто переносим проверку наличия класса со стадии линковки, указывая компилятору что проверка будет позже, в рантайме?
        Читал что плюсовики например говорят что такая практика им нравится с точки зрения аккуратного программирования: при отсутствии #import повсеместное использование #include может вызвать неприятности с cross-linking и компилятор будет ругаться а директива @class как раз дает возможность аккуратнее линковать файлы друг к другу…
        Рад был бы получить Ваши комментарии.

        • Alex Denisov

          Это все щее compile-time, мы просто обещаем компилятору, что этот класс будет определен в другой единице трансляции.
          Cross-linking это не проблема только C++, этого же можно добиться и в ObjC.

          Собственно, forward declaration решает две задачи: cross-linking и уменьшение времени (ре-)компиляции.

Want to get more of Railsware blog?

RSS FEED

We're always ready to help!

CONTACT US