Objective-C Protocol Forward Declarations

edelaney05 picture edelaney05 · Jul 18, 2012 · Viewed 32.6k times · Source

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?

Answer

newacct picture newacct · Jul 18, 2012

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