views:

29

answers:

3

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?

+1  A: 
  1. 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
    }
    
  2. You can send otherMethods message another way (you may need to define theSender as NSObject here):

    if ([theSender respondsToSelector:@selector(otherMethods)])
        [theSender performSelector:@selector(otherMethods)];
    
  3. 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
    
Vladimir
That isn't actually the problem here, though. Protocols do solve the problem, but only by solving the real problem first.
bbum
A: 
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.

bbum
+1  A: 

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
dreamlax
abundantly clear, thanks.
bitcruncher