从子视图调用超级视图函数
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”
【问题讨论】:
超类不知道子类。 是的..但我在子类中进行此检查... 是的,但这仍然不能让超类知道子类。你不是在编辑超类,是吗? 我认为通过超级视图实现的协议使超级视图成为子视图的代表,您正在尝试做的事情会更好。 顺便说一句,您通常使用isKindOfClass
或isMemberOfClass
检查班级成员资格。
【参考方案1】:
尝试只投射结果:
ProductView *p = (ProductView *)[self superview];
【讨论】:
【参考方案2】:根据我的评论,您可能最好使用委托模式。
我知道这比简单地检查父类的类类型要多得多,但它为您提供了更多功能,因为它将Product
和Postcode
类解耦。因此,实现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;
这是安全的,不会发出警告,也不需要强制转换。这是可行的,因为已知ProductView
是UIView
的子类。
【讨论】:
是的,很酷,谢谢...为了避免它在运行时崩溃,我仔细检查了超类是否属于 ProductView 类型。 IE。if ([[self superview] class] == [ProductView class])
是的,这很好。我是在做一个一般性的陈述。由于您进行了适当的运行时检查,因此您是安全的。以上是关于从子视图调用超级视图函数的主要内容,如果未能解决你的问题,请参考以下文章