Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C Protocol Forward Declarations

ObjectProperties.h

@protocol ObjectProperties <NSObject>  @property (strong, nonatomic) NSString *name; @property (strong, nonatomic) NSDate *date; @property (assign, nonatomic) int64_t index;  @end 

ClassA.h

#import <Foundation/Foundation.h>  @protocol ObjectProperties;  @interface ClassA : NSObject <ObjectProperties>  - (void)specialSauce;  @end; 

ManagedClassA.h

#import <CoreData/CoreData.h>  @protocol ObjectProperties;  @interface ManagedClassA : NSManagedObject <ObjectProperties>  - (void)doSomething;  @end; 

From the code example above, I have defined a protocol in a .h file to be used with both Core Data objects as well as plain ol' vanilla objects. It seems like "noise" to have conforming classes ‪#import‬ the protocol in the their header; it would be cleaner to forward declare the protocol & import‬ in the implementation file as I've shown above. However, Xcode throws a warning when doing it this way:

Cannot find protocol definition for 'ObjectProperties'

The code compiles, and mostly works. I say mostly because there's some funkiness with Core Data trying to dynamically create the getters / setters for the scalar property, but I think that's probably because I've hit an edge case.

Of course, the most obvious work around is to just import the protocol header into the class headers.

If my understanding is correct (and my knowledge is very recently acquired, and so it's entirely possible that I'm wrong), if I import the protocol into my class headers and make a change to the protocol, then all subsequent files that import my classes will have to be recompiled.

What is the correct way to do solve this type of problem?

like image 555
edelaney05 Avatar asked Jul 18 '12 00:07

edelaney05


People also ask

What are forward declarations C?

As others stated before, a forward declaration in C/C++ is the declaration of something with the actual definition unavailable. Its a declaration telling the compiler "there is a data type ABC".

Why should I use forward declarations?

A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier. In the case of functions, this allows us to tell the compiler about the existence of a function before we define the function's body.

What is Objective-C protocol?

Objective-C allows you to define protocols, which declare the methods expected to be used for a particular situation. This chapter describes the syntax to define a formal protocol, and explains how to mark a class interface as conforming to a protocol, which means that the class must implement the required methods.


2 Answers

You cannot forward declare a superclass or a protocol that it conforms to. In those cases, you must include the header. This is because (in the case of superclass) the superclass's instance variables and methods become part of your class; or (in the case of protocols) the protocol's methods become methods declared in your class, without needing to declare them explicitly. (i.e. Now other people who include your class's header will see that your class declares those methods, as if you declared them yourself.) The only way that that could be possible is if they were already defined in this scope, i.e. their headers are imported.

#import <SomeClass.h> #import <SomeProtocol.h> // these two must be imported  @interface MyClass : SomeClass <SomeProtocol> @end 

Forward declarations are useful for things that just show up in the type of a variable (specifically, an object pointer variable). Object pointers are all the same size and there is no difference between different types of object pointers at runtime (the concept of type of object pointer is just a compile-time thing). So there is no real need to know exactly what's in the classes of those types. Thus they can be forward declared.

@class SomeClass; @protocol SomeProtocol; // you can forward-declare these  @interface MyClass {     SomeClass *var1;     id<SomeProtocol> var2; } @end 
like image 197
newacct Avatar answered Sep 19 '22 09:09

newacct


Yes you are correct that all of the files will need to be recompiled, but this is necessary. Files that import the class header need to know the methods associated with the protocol it implements. If you tuck that definition away in the .m file then it is only visible to one file (since .m files never get imported). It's not the same as forward declaring classes. If you forward declare a protocol, you must declare it somewhere that is visible in the same scope as the forward declaration. I can't think of any example where this doesn't occur in the same file.

In ARC this is an error, because ARC needs to know about the memory management of the declared methods (do they return +1 instances, internal pointers, etc?)

like image 22
borrrden Avatar answered Sep 18 '22 09:09

borrrden