UIView / CALayer的通用类/协议 - 软件设计问题

时间:2011-03-03 15:15:50

标签: iphone uiview protocols class-design calayer

关于使用iOS SDK的一些软件设计决策,我有一个非常简单的问题。

假设我有一个管理应用程序中视图对象表示的类(UIManager)。此类允许外部控制器类向其添加视图对象。视图对象可以有两种:CALayerUIView子类。

我的问题是哪个界面更适合此类UIManager类。 例如:

@interface UIManager : UIView {}

// 1)
- (void)addGenericViewObject:(id)genericViewObject;

// 2)
- (void)addUIViewObject:(UIView*)uiViewObject;
- (void)addCALayerObject:(CALayer*)caLayerObject;

// 3)
- (void)addMyProtocolTypeViewObject(id<MyProtocolType>)myProtocolTypeViewObject;
@end

1)id类型太通用了吗?

2)对每种类型使用不同的方法签名会导致可怕的代码重复吗?

3)有没有办法通过UIView来表示CALayer<MyProtocolType>类?

或者更一般地说,让处理这些不同对象的类可以互换是不是很好?

UIManager的实现将是这样的:

@implementation UIManager

// 1)
- (void)addGenericViewObject:(id)genericViewObject {
    if ([genericViewObject isKindOfClass:[UIView class]]) {
        [_uiViewsContainer addSubview:(UIView*)genericViewObject];
    } else if ([genericViewObject isKindOfClass:[CALayer class]]) {
        [_caLayersContainer addSublayer:(CALayer*)genericViewObject];
    }
}
@end

类型检查总是很糟糕,可能有<MyProtocolType>可以解决这种情况,但是,我怎样才能在协议中表示UIViewCALayer类?这两个类都符合<NSObject>

提前致谢

1 个答案:

答案 0 :(得分:1)

类型检查是非常必要的。我认为有可能将问题重新构思为......“我希望经理能够接受UIView或CALayer并对他们做不同的事情,但拒绝所有其他事情。”在这种情况下,类型检查胜过hackery和我全心全意地建议您只需键入检查,并在事情没有按预期进行时抛出异常。

可以向CALayer和UIView添加一个非常非常私密的私有类别,例如具有64个字符的随机标识符的私有类别,它将类符合自定义协议,并且只检查符合性。但这样做会进行类型检查,并且是一项非常多的(不必要的)工作;上次我试过,GCC似乎讨厌这个。

我认为这可行,如果你以后在处理很多课程:

- (BOOL) addInterfaceObject:(id)anObject {

    void (^handler)();

    if (!(handler = [self interfaceObjectHandlerForClass:[anObject class]]))
    return NO;  // Or throw an exception

    handler(anObject);
    return YES;

}

- (void(^)(id anObject)) interfaceObjectHandlerForClass:(Class)aClass {

//  Or retrieve copy-autoreleased blocks from a dictionary

    if ([aClass isSubclassOfClass:[UIView class]])
    return ^ (id anObject) { [self.view addSubview:(UIView *)anObject]; };

    if ([aClass isSubclassOfClass:[CALayer class]])
    return ^ (id anObject) { [self.view.layer addSublayer:(CALayer *)anObject]; };

    return nil;

}