简体   繁体   中英

Calling super view function from sub view

I have a UIView called Product , which contains a sub UIView called Postcode .

In the Postcode UIView i have a simple form (one UITextField and one UIButton ).

When the UIButton is clicked a method (called -storeData ) is run inside postcode view ... which works as intended.

Now inside storeData I would like to call a method in the superview Product.

This is what i tried doing, but im getting a warning:

if ([[self superview] class] == [ProductView class]) {
        ProductView *p = [self superview]; 
        [p handlePostChange]; 
    }

// Get this warning from this line ProductView *p = [self superview];

PostView.m:124:28: Incompatible pointer types initializing 'ProductView *__strong' with an expression of type 'UIView *'

尝试仅投射结果:

ProductView *p = (ProductView *)[self superview];

As per my comment you may be better off using a delegation pattern.

I know it is a lot more code than simply checking the class type of the parent, but it gains you a lot more capability as it decouples the Product and Postcode classes. Thus the class that implements the handlePostChangeFor: method no longer has to be Product - it can be any class as long as it implements the SuperProtocol . Which in turn means you never have to check the class type inside Postocde , as you no longer care about it - all you care about is that some other class can do the work you want. Also if the superHandlerDelegate property in the instance of a Postcode is never set and remains nil you are still OK as Objective-c allows messages to be sent to nil .

Note that the code below is done in very broad brushstrokes and I have left a lot of extraneous stuff out. One main difference between your code and this example is that you now have to carry a parameter in the handlePostChangeFor: method to indicate which Postcode you are handling the change for. This is a direct result of having decoupled the two classes.

// Declare a protocol saying "Here is some functionality"
@protocol SuperProtocol
-(void) handlePostChangeFor:(Postcode*)postcode;
@end

// Product class says it will implement the functionality of the SuperProtocol
@interface Product : UIView <SuperProtocol>
@end

@implmementation Product
-(id)init
{
   if (!(self=[super init])) return self;
   ...
   // Create/locate the Postcode that is a child of this Product
   Postcode* postcode = ... // For example :- [[Postcode alloc] init];

   // Tell an instance of the Postcode class who will be supplying the SuperProtocol functionality
   postcode.superHandlerDelegate = self;
   ...
   return self;
}

// Implement the protocol's functionality
-(void) handlePostChangeFor:(Postcode*)postcode
{
  // Do Stuff with the data from the postcode instance
}
@end


@interface Postcode : UIView
// Identify who will implement the SuperProtocol functionality for this instance
@property (strong, nonatomic) id <SuperProtocol> superHandlerDelegate;
-(IBAction)storeData:(id)sender;
@end

@implementation Postcode
@synthesize superHandlerDelegate;
-(id)init
{
   if (!(self=[super init])) return self;
   ...
   // This is not required as NSObject's `alloc` sets everything to all zeroes
   // Note that you should not use "self.xxxxx" in an init method
   superHandlerDelegate = nil;
   ...
   return self;
}

-(IBAction)storeData:(id)sender
{
    ...
    // Tell the delegate to do the work
    [self.superHandlerDelegate handlePostChangeFor:self];
    ...
}

@end

The call to [self superview] returns a UIView pointer. You are trying to do the equivalent of:

UIView *view;
ProductView *p = view;

The compiler has no way to know that at runtime, view will really be of type ProductView . This is why the compiler complains.

The solution, as was stated, is to use a cast:

UIView *view;
ProductView *p = (ProductView *)view;

The cast tells the compiler "hey, don't worry, I know what I'm doing. It really is a ProductView ". Of course if you are wrong, the app will most likely crash at runtime.

The following is perfectly fine:

ProductView *p;
UIView *view = p;

This is safe, gives no warning, and requires no cast. This works because it is known that ProductView is a subclass of UIView .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM