Dynamically typed class generates compiler warnings on method selection
-
20-09-2019 - |
Question
Perhaps this is the wrong way to go about this, but it seems like such a clean and workable approach that I wonder how I can make the compiler warning go away?
@interface SomeView : UIView {
NSString *stringOfsomeImportance;
RelatedClass *niftyService;
}
@property (nonatomic, copy) NSString * stringOfnoImportance;
@property (nonatomic, retain) RelatedClass *niftyService;
@implementation
-(void)someMethod;
-(void)otherMethods;
@implementation RelatedClass *pvSomeObj = [[RelatedClass alloc] initWithSender:self];
[self setNiftyService:pvSomeObj];
Now, looking at the RelatedClass implementations...
@interface RelatedClass : NSObject {
id thesender;
@property (nonatomic, retain) id thesender;
@implementation
[thesender otherMethods]; // this generates a compiler warning
// that otherMethods cannot be found
// in SomeView, though it *is* found
// and seems to execute just fine
This seems like a valid approach, so I'm left wondering why the warning? Is there a way to better "explain" this to the compiler?
Could someone kindly share if this type of linkage is encouraged or if there is a better way to link two related, interdependent classes that need to communicate with one another?
I can't statically declare the sender object (SomeView) in RelatedClass because that seems to cause a recursion problem, as SomeView is defined with RelatedClass as a member...
Any suggestions?
Solution
You can define a protocol and say that your
thesender
object must conform to it:@protocol MyProtocol -(void)otherMethods; @end @interface RelatedClass : NSObject { id<MyProtocol> thesender; // Now compiler knows that thesender must respond // to otherMethods and won't generate warnings }
You can send
otherMethods
message another way (you may need to definetheSender
as NSObject here):if ([theSender respondsToSelector:@selector(otherMethods)]) [theSender performSelector:@selector(otherMethods)];
Edit: Actually you can also define thesender as SomeView* in your RelatedClass using forward class declaration:
//SomeView.h @class RelatedClass; @interface SomeView : UIView { RelatedClass *niftyService; } // then include RelatedClass.h in SomeView.m //RelatedView.h @class SomeView; @interface RelatedClass : NSObject { SomeView* thesender; } // then include SomeView.h in RelatedClass.m
OTHER TIPS
In your headers, you can forward declare classes that you want to use. In your implementation files, you can include the full header of those classes that you forward-declared.
For example:
SomeView.h
#import <FrameworkHeader.h>
// Here, you are saying that there is a class called RelatedClass, but it will be
// defined later.
@class RelatedClass;
@interface SomeView : UIView
{
RelatedClass *niftyService;
}
@end
SomeView.m
#import "SomeView.h"
#import "RelatedClass.h"
// By including "RelatedClass.h" you have fulfilled the forward declaration.
@implementation SomeView
// Can use "RelatedClass" methods from within here without warnings.
@end
RelatedClass.h
#import <FrameworkHeader.h>
@class SomeView;
@interface RelatedClass
{
SomeView *someView;
}
// methods
@end
RelatedClass.m
#import "RelatedClass.h"
#import "SomeView.h"
@implementation RelatedClass
// Can use "SomeView" methods from within here without warnings.
@end
id thesender = ....;
[thesender otherMethods]; // this generates a compiler warning
// that otherMethods cannot be found
// in SomeView, though it *is* found
// and seems to execute just fine
For the above to generate the warning as you describe, it is entirely because the method -otherMethods
has not been declared someplace where the compiler sees the declaration before attempting to compile the call site.
That is, the declaration of the method:
- (void) otherMethods;
Must appear in a header file that is imported -- directly or indirectly -- by the implementation file compiling that particular call site or the method declaration must appear in the @implementation
before the call site.