Common class/protocol for UIView/CALayer - software design issues
I have a very simple question regarding some software design decisions using the iOS SDK.
Suppose I have a class that manages the presentation of view objects in my application (UIManager
). This class allows external controller classes to add view objects to it. The view objects can be of two kinds: CALayer
and UIView
subclasses.
My question is which interface is more well suited for such UIManager
class.
For instance:
@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) The id
type is too generic?
2) Having a different method signature for each type can lead to awful code duplication?
3) Is there a way to represent both UIView
and CALayer
class through <My开发者_StackOverflowProtocolType>
?
Or more generally speaking, having class that handle these different objects interchangeable is not good?
The implementation of UIManager
would be something like this:
@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
Type checking is always bad, maybe having <MyProtocolType>
would solve the situation, however, how could I represent both UIView
and CALayer
class in a protocol? Both classes just conform to <NSObject>
.
Thanks in advance
Type checking is just so necessary. I think that it is possible to reframe the question to… “I want a manager to take either an UIView or a CALayer and do different things to them, but reject all the other things.” In that case, type checking trumps hackery and I wholeheartedly recommend that you just type-check, and throw an exception when things do not go as expected.
It is possible to add a private category that is really, really private, like one with a 64-character random identifier, to both CALayer and UIView, which conforms the classes to a custom protocol, and just check for conformity. But that does what type-checking does, and is an awful lot of (unnecessary) work; last time I tried, GCC appears to hate that.
I think this could work, if later on you are dealing with lots of classes:
- (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;
}
精彩评论