Reputation: 763
After watching iOS tech talks and reading up on class clusters I decided to extract legacy iOS 6 code to a private subclass:
@interface MyUIView : UIView @end // public
@interface MyUIViewiOS6 : MyUIView @end // private
@interface MyUIViewiOS7 : MyUIView @end // private
@implementation MyUIView
+ (id)alloc
{
// Don't loop on [super alloc]
if ([[self class] isSubclassOfClass:[MyUIView class]] &&
([self class] != [MyUIViewiOS6 class]) &&
([self class] != [MyUIViewiOS7 class]))
{
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
return [MyUIViewiOS6 alloc];
} else {
return [MyUIViewiOS7 alloc];
}
}
return [super alloc];
}
// Common implementation
@end
@implementation MyUIViewiOS6
// Legacy code
@end
@implementation MyUIViewiOS7
// iOS specific code
@end
This implementation works well until I want subclass MyUIView. For example if I create a subclass:
@interface MyRedUIView : MyUIView @end
and then init it like that:
[[MyRedUIView alloc] init]
object of type MyUIViewiOS6 or MyUIViewiOS7 will be allocated instead. Is there a way I can adapt this pattern to support subclassing, so that superclass of MyRedUIView is dynamically switched to MyUIViewiOS6 or MyUIViewiOS7?
Upvotes: 4
Views: 185
Reputation: 13986
You've reached the classic double-inheritance problem. You want to be either a RedUIView
or GreenUIView
and be either a MyUIViewiOS6
or a MyUIViewiOS7
view.
Since objective-c does not support double-inheritance, you'll have to decide the difference between what you are, and how you act. Anything that determines what you are, you put in the class. Anything that determines how you act goes into a @protocol
which then can be implemented.
I would subclass MyUIView
since MyUIViewiOS6
and MyUIViewiOS7
correspond to who you are, and then implement a Red
or Green
protocol for certain functionality:
@interface MyRedUIView : MyUIView<RedProtocol> @end
You can check to see if this class conforms to a specific protocol:
if ([class conformsToProtocol:@protocol(RedProtocol)]) {
self.color = [UIColor redColor];
}
If both of them really are who you are, then you have to use four separate classes.
Here's an example using categories. Assuming that you have MyUIView as specified in the question:
GreenView.h
#import "MyUIView.h"
#import "Green.h"
@interface MyUIView (GreenUIView) <Green>
-(BOOL) isGreen;
@end
@interface GreenView : MyUIView @end
GreenView.m
#import "GreenView.h"
@implementation MyUIView (GreenUIView)
-(BOOL) isGreen{
return [self conformsToProtocol:@protocol(Green)];
}
@end
@implementation GreenView @end
Green.h
@protocol Green <NSObject> @end
AppDelegate.m
#import "GreenView.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
GreenView* view = [[GreenView alloc] init];
NSLog(@"%@", [view isGreen]?@"yes":@"no");
return YES;
}
@end
Upvotes: 2