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

时间:2013-11-05 22:14:34

标签: ios objective-c nsarray protocols

我想允许不同观点之间的沟通。

我有两个较小的视图位于较大的视图之上,类似于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
    }
}
}

谢谢!我还在学习,所以请告诉我是否有更好的方法(不仅更容易,而且更好)。

4 个答案:

答案 0 :(得分:5)

ObjC没有泛型。如果有的话,有时会很好,但事实并非如此。但上述设计存在一些问题。

首先,如果viewArray应该只包含UIView个对象,那么它包含其他内容是一个编程错误。如果您发现它不是return则不行。如果您要在此处查看此内容,则应为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]类方法。

答案 1 :(得分:3)

如果你想在没有警告的情况下进行编译,你可以检查对象是否符合协议,然后将其转换为id<Protocol>

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

答案 2 :(得分: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)]; 
        }
    }
}

答案 3 :(得分:1)

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