Prajeet Shrestha
Prajeet Shrestha

Reputation: 8108

Protocol conformation error Objective C

In DataProvider.h

@protocol NewDataProviderProtocol 

- (void)fetchNewData;

@end

In SomeClass

#import DataProvider.h
@interface SomeClass :NSObject <NewDataProviderProtocol>

@end

When I try to make SomeClass conform to NewDataProviderProtocol it says,

No type or protocol named 'NewDataProviderProtocol'

It's weird since I already imported header DataProvider.h in which the protocol is declared.

So I forward declare the NewDataProviderProtocol before interface of SomeClass but xcode warns

Cannot find definition for **NewDataProviderProtocol**

What's the reason and the workaround for this?

Upvotes: 2

Views: 273

Answers (2)

Amin Negm-Awad
Amin Negm-Awad

Reputation: 16650

A. Reason

Likely you have a include cycle, because you import SomeClass.h into DataProvider.h, too. This leads to an undeclared identifier.

Why is it that way? Let's have an example:

// Foo.h
#import "Bar.h"
@interface Foo : NSObject 
…// Do something with Bar 
@end


// Bar.h
#import "Foo.h"
@interface Bar : NSObject 
…// Do something with Foo 
@end

If you compile, let's say Foo.h, the precompiler will expand this:

He gets …:

// Foo.h
#import "Bar.h"
@interface Foo : NSObject 
…// Do something with Bar 
@end

… imports Bar.h (And strips comments … But let's focus on the main topic.) …

// Foo.h
   // Bar.h
   #import "Foo.h"
   @interface Bar : NSObject 
   …// Do something with Foo 
   @end

@interface Foo : NSObject 
…// Do something with Bar 
@end

Foo.h will not be imported again, because it is already imported. Finally:

   // Bar.h
   @interface Bar : NSObject 
   …// Do something with Foo 
   @end

@interface Foo : NSObject 
…// Do something with Bar 
@end

This is quite clear: If A relies on B and B relies on A, it is impossible for a serial data stream as a file is, to have A ahead of B and B ahead of A at the same time. (Files are not subjects of the theory of relativity.)

B. Solution

In most cases you should give your code a hierarchy. (For many reasons. Having no import problems is one of the least important.) I. e. in your code an import of SomeClass.h into DataProvider.h looks strange.

Having such a problem is a code smell. Try to isolate and repair the reason for that. Do not move code pieces into different location to find a pace, where it works. This is code lottery.

C. Structure

Usually you have a class that expects others to conform to a protocol. Let's have an example:

// We declare the protocol here, because the class below expects from other classes to conform to the protocol.

@protocol DataSoure
…
@end

@interface Aggregator : NSObject 
- (void)addDataSource:(id<DataSource>)dataSource 
// We are using a protocol, because we do not want to restrict data sources to be subclass of a specific class.
// Therefore in this .h there cannot be an import of that – likely unknown - class
@end

SomeClass, that conforms to the protocol

#import "Aggregator.h"

@interface SomeClass:NSObject<DataSource>
…
@end

Upvotes: 1

Hemang
Hemang

Reputation: 27050

Two things to change:

Change definition like this:

@protocol NewDataProviderProtocol <NSObject>    
- (void)fetchNewData;    
@end

Why? Why tack a protocol of NSObject to a protocol implementation

Import DataProvider in SomeClass.m only. You can always create an extension of SomeClass inside implementation file where you can bind the protocol to conform a particular class.

@interface SomeClass ()<NewDataProviderProtocol>

@end

Why? It's the best practice. And to overcome forward class declaration errors. E.g. Objective-C: Forward Class Declaration

Upvotes: 0

Related Questions