I am trying to solve this, there are similar questions but none are fit for my issue
I have .h file with a a #protocol. The #interface needs to have that #protocol definition. But the #protocol needs the class's definition. Circular.
How can this be solved?
#protocol myProtocol
-(void)setupMyClass:(MyClass *)class;
#end
#inteface MyClass
#property (weak, nonatomic) id<myProtocol> delegate;
#end
If I use different files each needs to import the other, so that doesn't solve it
Forward-declare the class:
#class MyClass; // Forward declaration
#protocol MyProtocol
...
#end
#interface MyClass
...
#end
Related
Assume a class has been defined like this in OriginalObject.h:
#protocol OriginalDelegate;
#interface OriginalObject : NSObject {}
#property (nullable, nonatomic, weak) id<OriginalDelegate> delegate;
#end
#protocol OriginalDelegate <NSObject>
// … delegate method declarations …
#end
Now, in ExtendedObject.h, I want to do this:
#import "OriginalObject.h"
#protocol ExtendedDelegate;
#interface ExtendedObject : OriginalObject {}
#property (nullable, nonatomic, weak) id<ExtendedDelegate> delegate;
#end
#protocol ExtendedDelegate <OriginalDelegate>
// … additional delegate method declarations …
#end
Attempting this gives me the following warning on the #property … delegate; line of ExtendedObject.h:
Property type 'id<ExtendedDelegate> _Nullable' is incompatible with type 'id<OriginalDelegate> _Nullable' inherited from 'OriginalObject'
It appears that the compiler doesn't know ExtendedDelegate will conform to OriginalDelegate. Moving the full protocol declaration above the ExtendedObject interface in ExtendedObject.h resolves the warning:
#import "OriginalObject.h"
#protocol ExtendedDelegate <OriginalDelegate>
// … additional delegate method declarations …
#end
#interface ExtendedObject : OriginalObject {}
#property (nullable, nonatomic, weak) id<ExtendedDelegate> delegate;
#end
What I'd like to know is… is there any way to tell the compiler in the forward-declaration that ExtendedDelegate will conform to OriginalDelegate (enabling use of something more like the first version of ExtendedObject.h above)?
Neither of the following attempts at such a forward-declaration seem to be valid syntax:
#protocol ExtendedDelegate <OriginalDelegate>;
#protocol ExtendedDelegate : OriginalDelegate;
In my AnInterface.h file, I declare an interface, which has a property refers to another interface 'AProperty'. AProperty is defined in AProperty.h:
#interface AnInterface :UICollectionViewFlowLayout
#property (strong, nonatomic) AProperty *aProperty;
#end
How can I declare AProperty in AnInterface.h without import the AProperty.h? In C++, I can do something like 'class AProperty'. I can't import AProperty.h since it will create a circle import of .h files.
You can do a forward declaration:
#class AProperty;
But keep in mind that other classes will have to include the header for AProperty in order to access any of members of this class.
Assume you have a class and protocol:
#class MyClass;
#protocol Protocol
- (void)doSomethingWithClass:(MyClass*)myClass;
#end
#interface MyClass : NSObject
#property (weak) id<Protocol> delegate;
#end
Because protocol references MyClass type, compiler has to resolve it first. Since MyClass is declared after protocol, we need to let compiler know that class exists. This is where forward declarations get handy.
Similar to your C++ experience:
#class AProperty;
I have custom UIView class GestureView. I have a forward declaration for this class and it's delegate below. I have imported GestureView.h in .m file. This works fine but iOS gives warning message saying "Cannot find protocol definition for GestureViewDelegate". If I remove forward declaration it gives same warning message as error. I don't want to import GestureView.h from ContainerViewController.h as I usually imports stuffs in .m file. Could someone please explain what's wrong in following class structure?
ContainerViewController.h
#import <UIKit/UIKit.h>
#class DividerView;
#class GestureView;
#protocol GestureViewDelegate;
#interface ContainerViewController : UIViewController<GestureViewDelegate>
#property (strong, nonatomic) IBOutlet GestureView *topContentView;
#end
GestureView.h
#import <UIKit/UIKit.h>
#protocol GestureViewDelegate;
#interface GestureView : UIView
- (void)initialiseGestures:(id)delegate;
#end
#protocol GestureViewDelegate <NSObject>
#required
- (void)GestureView:(GestureView*)view handleSignleTap:(UITapGestureRecognizer*)recognizer;
#end
I like that you're trying to avoid imports in header files: very good practice. However, to fix your bug you can just make your code even better! In my opinion it's not really necessary that your ContainerViewController class outwardly declares that it supports GestureViewDelegate protocol, so you should move this into your implementation file. Like so:
GestureView.h
#import <UIKit/UIKit.h>
#protocol GestureViewDelegate;
#interface GestureView : UIView
- (void)initialiseGestures:(id <GestureViewDelegate>)delegate;
#end
#protocol GestureViewDelegate <NSObject>
#required
- (void)gestureView:(GestureView *)view handleSingleTap:(UITapGestureRecognizer *)recognizer;
#end
ContainerViewController.h
#import <UIKit/UIKit.h>
#class GestureView;
#interface CollectionViewController : UIViewController
// this property is declared as readonly because external classes don't need to modify the value (I guessed seen as it was an IBOutlet)
#property (strong, nonatomic, readonly) GestureView *topContentView;
#end
ContainerViewController.m
#import "ContainerViewController.h"
#import "GestureView.h"
// this private interface declares that GestureViewDelegate is supported
#interface CollectionViewController () <GestureViewDelegate>
// the view is redeclared in the implementation file as readwrite and IBOutlet
#property (strong, nonatomic) IBOutlet GestureView *topContentView;
#end
#implementation ContainerViewController
// your implementation code goes here
#end
Try this way, and please reply if it works or not.
GestureView.h
#import <UIKit/UIKit.h>
#protocol GestureViewDelegate <NSObject>
#required
- (void)GestureView:(GestureView*)view handleSignleTap:(UITapGestureRecognizer*)recognizer;
#end
#interface GestureView : UIView
- (void)initialiseGestures:(id)delegate;
#end
ContainerView.h
#import <UIKit/UIKit.h>
#class DividerView;
#class GestureView;
/*#protocol GestureViewDelegate;*/ //NO NEED TO WRITE THIS
#interface ContainerViewController : UIViewController<GestureViewDelegate>
#property (strong, nonatomic) IBOutlet GestureView *topContentView;
#end
I have a protocol like this:
#import <Foundation/Foundation.h>
#protocol Prot1 <NSObject>
#required
- (void)methodInProtocol;
#end
This is a protocol for a delegate I want to store in a class like this:
#import <Cocoa/Cocoa.h>
#class Prot1;
#interface Class1 : NSObject
#property (nonatomic, strong) Prot1 *delegate;
- (void)methodInClass;
#end
The implementation for this class is like this:
#import "Class1.h"
#import "Prot1.h"
#implementation Class1
#synthesize delegate;
- (void)methodInClass {
[delegate methodInProt];
}
#end
When I build these pieces of code, I get the following error:
Receiver type 'Prot1' for instance message is a forward declaration
What is wrong here? I did understand that I have to do a forward declaration via #class for the protocol and I thought I only had to #import the protocol, in the class implementation... Isn't that right?
As it isnt a class, you have to define it as what it is - a protocol ;)
Use forward declaration: #protocol Prot1;;
And use the property like that:
#property (nonatomic, strong) id<Prot1> delegate;
In subclassing a class, I want to also subclass a delegate of the parent class given that the subclass now has additional functionality. What's the best way to go about doing this? If I just declare another delegate property in the subclass with the same name I would get a warning "Property type 'id' is incompatible with type 'id' inherited from 'ParentClass'
Given this example that produces the warning:
// Class A
#protocol ClassADelegete;
#interface ClassA : NSObject
#property (nonatomic, weak) id<ClassADelegete> delegate;
#end
#protocol ClassADelegete <NSObject>
- (void)classADidSomethingInteresting:(ClassA *)classA;
#end
// Class B
#protocol ClassBDelegete;
#interface ClassB : ClassA
#property (nonatomic, weak) id<ClassBDelegete> delegate; // Warning here
#end
#protocol ClassBDelegete <ClassADelegete>
- (void)classBDidSomethingElse:(ClassB *)classB;
#end
Two solutions that remove the warning are.
1) In the subclass, place the protocol definition before the class definition. This is what UITableViewDelegate in UITableView.h does:
// Class B
#class ClassB;
#protocol ClassBDelegete <ClassADelegete>
- (void)classBDidSomethingElse:(ClassB *)classB;
#end
#interface ClassB : ClassA
#property (nonatomic, weak) id<ClassBDelegete> delegate;
#end
2) In the subclass, add the original protocol alongside the new one:
// Class B
#protocol ClassBDelegete;
#interface ClassB : ClassA
#property (nonatomic, weak) id<ClassADelegete, ClassBDelegete> delegate;
#end
#protocol ClassBDelegete <ClassADelegete>
- (void)classBDidSomethingElse:(ClassB *)classB;
#end
I assume (1) works as Apple do it this way, Option (2) removes the warning but I haven't compiled and run anything setup this way.
Follow the example of NSTableView and NSOutlineView.
NSOutlineView is a subclass of NSTableView, and defines its own protocol for its dataSource and delegate.
NSTableView declares its delegate this way:
- (void)setDelegate:(id <NSTableViewDelegate>)delegate;
- (id <NSTableViewDelegate>)delegate;
and NSOutlineView:
- (void)setDelegate:(id <NSOutlineViewDelegate>)anObject;
- (id <NSOutlineViewDelegate>)delegate;
Apparently the compiler is more lenient with bare method declarations than it is with property declarations.
Unlike NSTable/OutlineView, you might want to make the subclass's protocol inherit from the base class's protocol, e.g.
#protocol SpecializedProtocol <BaseProtocol>
... it probably depends on the situation.