从子视图调用超级视图函数

Posted

技术标签:

【中文标题】从子视图调用超级视图函数【英文标题】:Calling super view function from sub view 【发布时间】:2012-12-09 23:41:36 【问题描述】:

我有一个名为 Product 的 UIView,其中包含一个名为 Postcode 的子 UIView。

在邮政编码UIView 中,我有一个简单的表格(一个UITextField 和一个UIButton)。

当单击UIButton 时,一个方法(称为-storeData)会在邮政编码视图中运行...按预期工作。

现在在storeData里面我想调用superview Product中的一个方法。

这是我尝试做的,但我收到警告:

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

// 从这一行得到这个警告ProductView *p = [self superview];

PostView.m:124:28:初始化不兼容的指针类型 带有“UIView *”类型表达式的“ProductView *__strong”

【问题讨论】:

超类不知道子类。 是的..但我在子类中进行此检查... 是的,但这仍然不能让超类知道子类。你不是在编辑超类,是吗? 我认为通过超级视图实现的协议使超级视图成为子视图的代表,您正在尝试做的事情会更好。 顺便说一句,您通常使用isKindOfClassisMemberOfClass 检查班级成员资格。 【参考方案1】:

尝试只投射结果:

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

【讨论】:

【参考方案2】:

根据我的评论,您可能最好使用委托模式。

我知道这比简单地检查父类的类类型要多得多,但它为您提供了更多功能,因为它将ProductPostcode 类解耦。因此,实现handlePostChangeFor: 方法的类不再必须是Product——它可以是任何类,只要它实现了SuperProtocol。这反过来意味着您永远不必检查 Postocde 中的类类型,因为您不再关心它 - 您所关心的只是其他类可以完成您想要的工作。此外,如果 Postcode 实例中的 superHandlerDelegate 属性从未设置并保持为 nil 您仍然可以,因为 Objective-c 允许将消息发送到 nil

请注意,下面的代码是用非常广泛的笔触完成的,我遗漏了很多无关的东西。您的代码与此示例之间的一个主要区别是,您现在必须在 handlePostChangeFor: 方法中携带一个参数,以指示您正在为哪个邮政编码处理更改。这是解耦这两个类的直接结果。

// 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

【讨论】:

【参考方案3】:

[self superview] 的调用返回一个UIView 指针。您正在尝试执行以下操作:

UIView *view;
ProductView *p = view;

编译器无法知道在运行时,view 是否真的是ProductView 类型。这就是编译器抱怨的原因。

如前所述,解决方案是使用演员表:

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

演员告诉编译器“嘿,别担心,我知道我在做什么。它真的是ProductView”。当然,如果你错了,应用程序很可能会在运行时崩溃。

以下是完全没问题的:

ProductView *p;
UIView *view = p;

这是安全的,不会发出警告,也不需要强制转换。这是可行的,因为已知ProductViewUIView 的子类。

【讨论】:

是的,很酷,谢谢...为了避免它在运行时崩溃,我仔细检查了超类是否属于 ProductView 类型。 IE。 if ([[self superview] class] == [ProductView class]) 是的,这很好。我是在做一个一般性的陈述。由于您进行了适当的运行时检查,因此您是安全的。

以上是关于从子视图调用超级视图函数的主要内容,如果未能解决你的问题,请参考以下文章

如何知道何时从子视图中单击了超级视图中的选项卡项

在 Cocoa,UIResponder 中将消息从子视图发送到父视图?

如何在运行时从超级视图中删除视图?

从子视图中的路径对象在 UIView 中构建剪辑区域

从子视图控制器调用函数不起作用

从另一个类创建超级视图的子视图不起作用