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;
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;
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
Is it possible to encapsulate the fact that my class is derived from a certain superclass? Something like:
#class NoneOfYourBusiness;
#interface MyClass : NoneOfYourBusiness
#end
The compiler doesn’t like this: Attempting to use the forward class 'NoneOfYourBusiness' as superclass of 'MyClass'.
You could add some indirection; a dummy superclass in the inheritance tree, between MyClass and RealSuperclass:
Private header, HiddenSuperclass.h, with corresponding implementation file
#import <Foundation/Foundation.h>
#interface HiddenSuper : NSObject
- (void)makePancakes;
#end
Header for dummy class, corresponding empty implementation
#import <Foundation/Foundation.h>
#import "HiddenSuper.h"
#interface DummySuper : HiddenSuper
// Nothing to see here, folks!
#end
Then your public class's header:
#import "DummySuper.h"
#interface PublicSubclass : DummySuper
- (void)fixBreakfast;
#end
And the implementation, hidden by compilation:
#import "PublicSubclass.h"
#import "HiddenSuper.h"
#implementation PublicSubclass
- (void)fixBreakfast
{
[self makePancakes];
}
#end
Two answers
The requirement makes no sense. Client code can see the super class does not mean anything because it should be empty.
i.e. Thats all they can see
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClass : NoneOfYourBusiness
- (void)publicMethod;
#end
because you should put all private / internal method / variable in private header / implementation file.
Ok you really need to hide it for some reason, then hide everything
public header
#interface MyClass : NSObject
- (void)publicMethod;
#end
private header / implementation file
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClassImpl : NoneOfYourBusiness
- (void)publicMethod;
#end
#interface MyClass ()
#property (strong) MyClassImpl *impl;
#end
#implementation
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.impl;
}
#end
you can even make MyClass inherited from NSProxy to make it a real proxy object
I need to have property in class that is excluded from public framework headers, but it is available for use internally in other framework classes.
What I did right now is:
MyClass.h:
#interface MyClass: NSObject
#end
MyClass+Internal.h
#interface MyClass (Internal)
#property (nonatomic, copy) NSString *mySecretProperty;
#end
MyClass.m
#import "MyClass.h"
#import "MyClass+Internal.h"
#interface MyClass ()
#property (nonatomic, copy) NSString *mySecretProperty;
#end
#implementation MyClass
#end
And I can use private property like:
MyOtherClass.m:
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyOtherClass
- (void)test {
MyClass *myClass = [MyClass new];
NSLog(#"%#", myClass.mySecretProperty)
}
#end
But what I don't like about this setup is that I have duplicate declaration of property in my Internal Category and inside of anonymous Category.
Is there a way to improve this setup?
I think you could do with the class extension only, there is no need to use a category. The quick fix would be to remove the category name from the parenthesis, transforming it into the class extension, then remove the class extension declaration from the .m file.
After this you only import the extension header in your framework classes and you make sure it is a private header of your framework.
MyClass.h
#interface MyClass: NSObject
#end
MyClass+Internal.h
#import "MyClass.h"
#interface MyClass ()
#property (nonatomic, copy) NSString *mySecretProperty;
#end
MyClass.m
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyClass
#end
MyOtherClass.m:
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyOtherClass
- (void)test {
MyClass *myClass = [MyClass new];
NSLog(#"%#", myClass.mySecretProperty)
}
#end
The key is understanding the difference between categories and class extensions, see here: https://stackoverflow.com/a/4540582/703809
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