{"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 class=\"\" data-line=\"\">cmake<\/code> utility.\r\n\r\nSo, here is&#8230;\r\n\r\nEmpty class <code class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">main.m<\/code> as a driver &#8211; it just creates <code class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">Armor<\/code> class in order to compile these changes.\r\n\r\nThe first approach is to use <code class=\"\" data-line=\"\">#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 class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">wearArmor:<\/code> method, but haven&#8217;t included <code class=\"\" data-line=\"\">Armor<\/code> yet.\r\n\r\nNow we&#8217;ll go another way:\r\n\r\nUse <code class=\"\" data-line=\"\">#import<\/code> at implementation (<code class=\"\" data-line=\"\">Warrior.m<\/code>) and forward declaration (<code class=\"\" data-line=\"\">@class Armor;<\/code>) at header (<code class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">isMagical<\/code> from <code class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">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 class=\"\" data-line=\"\">@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,"inline_featured_image":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\/2017\/12\/Using-Forward-Declaration.png","article_background":"","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}]}}