{"id":5217,"date":"2013-08-09T14:10:34","date_gmt":"2013-08-09T11:10:34","guid":{"rendered":"http:\/\/railsware.com\/blog\/?p=5217"},"modified":"2020-10-26T19:31:18","modified_gmt":"2020-10-26T16:31:18","slug":"using-forward-declaration-in-your-objective-c-projects","status":"publish","type":"post","link":"https:\/\/railsware.com\/blog\/using-forward-declaration-in-your-objective-c-projects\/","title":{"rendered":"Using Forward Declaration In Your Objective-C Projects"},"content":{"rendered":"<a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/08\/Screen-Shot-2013-08-08-at-16.56.23.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-5243 size-full\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/08\/Screen-Shot-2013-08-08-at-16.56.23.png\" alt=\"Screen Shot 2013-08-08 at 16.56.23\" width=\"594\" height=\"338\" \/><\/a>\r\n\r\nIf you&#8217;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.\r\n\r\nSo, let&#8217;s skip the theory and jump right into a small example to see what it&#8217;s all about.\r\n\r\nWe&#8217;ll create a small project, that is quite useless, but will at the same time serve as a good example and <code>cmake<\/code> utility.\r\n\r\nSo, here is&#8230;\r\n\r\nEmpty class <code>Warrior<\/code>\r\n<pre lang=\"objc\" title=\"Warrior.h\">\/\/ Warrior.h\r\n#import &lt;Foundation\/Foundation.h&gt;\r\n\r\n@interface Warrior : NSObject\r\n\r\n@end\r\n<\/pre>\r\n<pre lang=\"objc\" title=\"Warrior.m\">\/\/ Warrior.m\r\n#import \"Warrior.h\"\r\n\r\n@implementation Warrior\r\n\r\n@end\r\n<\/pre>\r\nEmpty class <code>Armor<\/code>\r\n<pre lang=\"objc\" title=\"Armor.h\">\/\/ Armor.h\r\n#import &lt;Foundation\/Foundation.h&gt;\r\n\r\n@interface Armor : NSObject\r\n\r\n@end\r\n<\/pre>\r\n<pre lang=\"objc\" title=\"Armor.m\">\/\/ Armor.m\r\n#import \"Armor.h\"\r\n\r\n@implementation Armor\r\n\r\n@end\r\n<\/pre>\r\n<code>main.m<\/code> as a driver &#8211; it just creates <code>Warrior<\/code> object and prints it\r\n<pre lang=\"objc\" title=\"main.m\">\/\/ main.m\r\n#import &lt;Foundation\/Foundation.h&gt;\r\n#import \"Warrior.h\"\r\n\r\nint main() {\r\n    Warrior *w = [Warrior new];\r\n    NSLog(@\"%@\", w);\r\n    return 0;\r\n}\r\n<\/pre>\r\nAnd <code>cmake<\/code> configuration file\r\n<pre lang=\"objc\" title=\"CMakeLists.txt\">\/\/ CMakeLists.txt\r\ncmake_minimum_required(VERSION 2.8)\r\n\r\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -framework Foundation\")\r\n\r\nset(SOURCES Warrior.m Armor.m main.m)\r\nadd_executable(fdecl ${SOURCES})\r\n<\/pre>\r\nSo, let&#8217;s build our simple program\r\n<pre class=\"theme:terminal lang:sh decode:true\">$ cd directory_with_project\r\n$ cmake . # prepare makefile\r\n$ make # build\r\n<\/pre>\r\nWe see which modules are being built\r\n<pre class=\"theme:terminal lang:sh decode:true\">Scanning dependencies of target fdecl\r\n[ 33%] Building CXX object CMakeFiles\/fdecl.dir\/Warrior.m.o\r\n[ 66%] Building CXX object CMakeFiles\/fdecl.dir\/Armor.m.o\r\n[100%] Building CXX object CMakeFiles\/fdecl.dir\/main.m.o\r\nLinking CXX executable fdecl\r\n[100%] Built target fdecl\r\n<\/pre>\r\nAnd now we&#8217;ll add an ability to wear armor\r\n<pre lang=\"objc\" title=\"Warrior.h\">\/\/ Warrior.h\r\n@interface Warrior : NSObject\r\n\r\n- (void)wearArmor:(Armor *)armor;\r\n\r\n@end\r\n<\/pre>\r\n<pre lang=\"objc\" title=\"Warrior.m\">\/\/ Warrior.m\r\n#import \"Warrior.h\"\r\n\r\n@implementation Warrior\r\n{\r\n    Armor *_armor;\r\n}\r\n\r\n- (void)wearArmor:(Armor *)armor\r\n{\r\n    _armor = armor;\r\n}\r\n\r\n@end\r\n<\/pre>\r\n<i>Remember this state, we&#8217;ll get back to it later.<\/i>\r\n\r\nWe need to inform compiler about the <code>Armor<\/code> class in order to compile these changes.\r\n\r\nThe first approach is to use <code>#include\/#import<\/code> statements and it&#8217;s being used by a lot of developers.\r\n\r\nSo let&#8217;s do it\r\n<pre lang=\"objc\" title=\"Warrior.h\">\/\/ Warrior.h\r\n#import \"Armor.h\"\r\n\r\n@interface Warrior : NSObject\r\n\r\n- (void)wearArmor:(Armor *)armor;\r\n\r\n@end\r\n<\/pre>\r\nand build\r\n<pre class=\"theme:terminal lang:sh decode:true\">$ make\r\nScanning dependencies of target fdecl\r\n[ 33%] Building CXX object CMakeFiles\/fdecl.dir\/Warrior.m.o\r\n[ 66%] Building CXX object CMakeFiles\/fdecl.dir\/main.m.o\r\nLinking CXX executable fdecl\r\n[100%] Built target fdecl\r\n<\/pre>\r\nLooks good, but let&#8217;s add some property to our instance of <code>Armor<\/code> class, e.g. &#8216;is it magical?&#8217;\r\n<pre lang=\"objc\" title=\"Armor.h\">\/\/ Armor.h\r\n#import &lt;Foundation\/Foundation.h&gt;\r\n\r\n@interface Armor : NSObject\r\n\r\n- (BOOL)isMagical;\r\n\r\n@end\r\n<\/pre>\r\n<pre lang=\"objc\" title=\"Armor.m\">\/\/ Armor.m\r\n#import \"Armor.h\"\r\n\r\n@implementation Armor \r\n\r\n- (BOOL)isMagical \r\n{\r\n    return YES;\r\n}\r\n\r\n@end\r\n<\/pre>\r\nand let&#8217;s build our program again\r\n<pre class=\"theme:terminal lang:sh decode:true\">$ make\r\nScanning dependencies of target fdecl\r\n[ 33%] Building CXX object CMakeFiles\/fdecl.dir\/Warrior.m.o\r\n[ 66%] Building CXX object CMakeFiles\/fdecl.dir\/Armor.m.o\r\n[100%] Building CXX object CMakeFiles\/fdecl.dir\/main.m.o\r\nLinking CXX executable fdecl\r\n[100%] Built target fdecl\r\n<\/pre>\r\nGood news is that the build of <code>main.m<\/code> was successful. There&#8217;s one thing though. Despite of the fact that the build has been successful, workflow has not been optimal &#8211; main doesn&#8217;t use <code>Armor<\/code>, therefore, it must know nothing about this class.\r\n\r\nOk, let&#8217;s get back to the state where we&#8217;ve added <code>wearArmor:<\/code> method, but haven&#8217;t included <code>Armor<\/code> yet.\r\n\r\nNow we&#8217;ll go another way:\r\n\r\nUse <code>#import<\/code> at implementation (<code>Warrior.m<\/code>) and forward declaration (<code>@class Armor;<\/code>) at header (<code>Warrior.h<\/code>)\r\n<pre lang=\"objc\" title=\"Warrior.h\">\/\/ Warrior.h\r\n@class Armor;\r\n\r\n@interface Warrior : NSObject\r\n\r\n- (void)wearArmor:(Armor *)armor;\r\n\r\n@end\r\n<\/pre>\r\n<pre lang=\"objc\" title=\"Warrior.m\">\/\/ Warrior.m\r\n#import \"Armor.h\"\r\n\r\n@implementation Warrior\r\n{\r\n    Armor *_armor;\r\n}\r\n\r\n- (void)wearArmor:(Armor *)armor\r\n{\r\n    _armor = armor;\r\n}\r\n@end\r\n<\/pre>\r\nMake it (make sure that you&#8217;ve removed <code>isMagical<\/code> from <code>Armor<\/code>, we need this to get the same experience as before)\r\n<pre class=\"theme:terminal lang:sh decode:true\">$ make\r\n<\/pre>\r\nAdd <code>isMagical<\/code> method again\r\n<pre lang=\"objc\" title=\"Armor.h\">\/\/ Armor.h\r\n#import &lt;Foundation\/Foundation.h&gt;\r\n\r\n@interface Armor : NSObject\r\n\r\n- (BOOL)isMagical;\r\n\r\n@end\r\n<\/pre>\r\n<pre lang=\"objc\" title=\"Armor.m\">\/\/ Armor.m\r\n#import \"Armor.h\"\r\n\r\n@implementation Armor \r\n\r\n- (BOOL)isMagical \r\n{\r\n    return YES;\r\n}\r\n\r\n@end\r\n<\/pre>\r\nBuild and check the results\r\n<pre class=\"theme:terminal lang:sh decode:true\">$ make\r\nScanning dependencies of target fdecl\r\n[ 33%] Building CXX object CMakeFiles\/fdecl.dir\/Warrior.m.o\r\n[ 66%] Building CXX object CMakeFiles\/fdecl.dir\/Armor.m.o\r\nLinking CXX executable fdecl\r\n[100%] Built target fdecl\r\n<\/pre>\r\nNow it looks much better. Did you notice an important difference?\r\n\r\nIn our example we have only three modules, so the benefit is barely noticeable.\r\n\r\nThings change dramatically when you&#8217;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&#8217;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.\r\n\r\nYou can experience exactly the same problems when using <code>@protocol<\/code>s as delegates.\r\n<pre lang=\"objc\" title=\"Awesome.h\">\/\/ Awesome.h\r\n@class Awesome;\r\n\r\n@protocol AwesomeDelegate\r\n\r\n- (void)awesome:(Awesome *)awesome didFailed:(NSError *)error;\r\n\r\n@end\r\n\r\n@interface Awesome : NSObject\r\n\r\n@property (weak, nonatomic) id delegate;\r\n\r\n@end\r\n\/\/ and then include this header into each class that want to be an awesome delegate\r\n<\/pre>\r\nSo the right way is to use different files for a delegate and a class, which use this a delegate:\r\n<pre lang=\"objc\" title=\"AwesomeDelegate.h\">\/\/ AwesomeDelegate.h\r\n@class Awesome;\r\n\r\n@protocol AwesomeDelegate\r\n\r\n- (void)awesome:(Awesome *)awesome didFailed:(NSError *)error;\r\n\r\n@end\r\n<\/pre>\r\n<pre lang=\"objc\" title=\"Awesome.h\">\/\/ Awesome.h\r\n@protocol AwesomeDelegate;\r\n\r\n@interface Awesome : NSObject\r\n\r\n@property (weak, nonatomic) id delegate;\r\n\r\n@end\r\n<\/pre>\r\nTo summarise, keep in mind the importance of forward declaration, as it might save your time dramatically with every build you run for the project.\r\n\r\nIn 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&#8217;s&#8230; no, not MasterCard, forward declaration in this case.","protected":false},"excerpt":{"rendered":"<p>If you&#8217;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&#8217;s skip the theory and jump right into a small example to see what it&#8217;s all about. We&#8217;ll create a small project, that is quite useless,&#8230;<\/p>\n","protected":false},"author":55,"featured_media":9471,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[],"coauthors":["AlexDenisov"],"class_list":["post-5217","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"aioseo_notices":[],"categories_data":[{"name":"Engineering","link":"https:\/\/railsware.com\/blog?category=development"}],"post_thumbnails":"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/08\/Screen-Shot-2013-08-08-at-16.56.23.png","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/5217","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/users\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/comments?post=5217"}],"version-history":[{"count":46,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/5217\/revisions"}],"predecessor-version":[{"id":12828,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/5217\/revisions\/12828"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media\/9471"}],"wp:attachment":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media?parent=5217"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/categories?post=5217"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/tags?post=5217"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/coauthors?post=5217"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}