如何强制数组中的对象符合特定协议?

5

我希望能够允许不同视图之间的通信。

我有两个较小的视图叠在一个大视图上,类似于iOS的视频播放器,但也有一些不同。当我点击大视图时,我想切换视图的出现和隐藏。我已经有了一个协议,所有的视图都符合该协议。我想将这些视图添加到另一个名为HideViewsService的类中,该类具有一个NSArray属性。我可以强制使用这个HideViewsService类并添加视图的类只添加符合这个协议的视图吗?或者只添加UIViews

此外,我想调用视图上的一个方法,我知道所有视图都有它,但我不知道如何通过编译器。这是我的-hideAllViews方法:

-(void)hideAllViews
{
for(int i=0; i<self.viewArray.count; i++)
{
    id obj = [self.viewArray objectAtIndex:i];
    if([obj isKindOfClass:[UIView class]] == false)
    {
        return;
    }
    UIView *view = (UIView *)obj;
    if([view respondsToSelector:@selector(hide)])
    {
        [view hide]; // the compiler obviously doesn't like this
    }
}
}

谢谢!我还在学习中,如果有更好的方法,请告诉我(不仅是更容易,而是更好)。


2
我自己从未这样做过,但这里有一个关于子类化NSArray的线程 - Mike D
你的意思是编译器不喜欢这个?你收到了一个警告? - ManicMonkOnMac
是的,出现了一个错误。如果我尝试构建它,它将无法构建。UIView没有名为-hide的公共方法。 - SirRupertIII
你是在使用自定义视图,还是声明了一个类别?你自定义的视图有 hide 方法吗? - ManicMonkOnMac
是的,自定义视图。 - SirRupertIII
3
不要创建NSArray的子类,只需检查并添加符合协议的项。 - zaph
4个回答

5
ObjC没有泛型。有时候如果它有泛型就好了,但它没有。但上述设计有几个问题。
首先,如果viewArray只应包含UIView对象,则其包含其他任何内容都是编程错误。如果你发现它不是这样的,那么仅仅返回是不可以的。如果你要在这里检查它,应该使用NSAssert()。同样,如果viewArray中的所有东西都应该响应hide,如果它没有响应,你不应该跳过它。这是许多微妙错误的根源。
更好的解决方案是在将对象添加到HideViewsService时控制添加的点(虽然有更好的方法来完成它;我们会介绍到)。
@protocol XYZHideableView <NSObject>
- (void)hide;
@end

@interface XYZHideViewsService
- (void)addHideableView:(id<XYZHideableView>)view;
- (void)removeHideableView:(id<XYZHideableView>)view;
@end

现在,您不必担心viewArray中是否包含响应于hide的内容。
话虽如此,我通常会使用NSNotificationCenter来实现这一点。可隐藏视图应该观察类似于XYZHideAllHideableViews的通知。当它们设置它时,它们应该隐藏自己。然后您就不需要一个HideViewsService。您只需要一个+[HideableView hideAllHideableViews]类方法。

3

如果您想编译时不出现警告,只需检查对象是否符合协议,然后将其转换为id<Protocol>

if ([view conformsToProtocol:@protocol(Protocol)]) {
    id<Protocol> conformingView = (id<Protocol>)view;
    // or
    UIView<Protocol> *conformingView = (UIView<Protocol>*)view;
}

1
使用标准方法检查对象是否符合协议:
 if ([object conformsToProtocol:Protocol]) {
    [array addObject:object];
}

而且我可以建议使用快速枚举吗?
-(void)hideAllViews
{
for(CustomView *view in self.viewArray)
    {
     if([view respondsToSelector:@selector(hide)])
        {
        [view performSelector:@selector(hide)]; 
        }
    }
}

1
if([obj respondToSelector:selector){  [obj performSelector:selector}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接