我有一个我一直在努力的通用iOS应用程序。在大多数情况下,我一直在通过创建子类来处理设备差异,因此RootViewController由RootViewController-iPad和RootViewController-iPhone子类化。模式从main.m开始,我在那里进行设备检测:
int retVal;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
retVal = UIApplicationMain(argc, argv, nil, @"SalesPadAppDelegate_iPad");
} else {
retVal = UIApplicationMain(argc, argv, nil, @"SalesPadAppDelegate_iPhone");
}
这种模式运行良好,可以最大限度地减少代码重用。
在堆栈的下方,我有一系列视图控制器,它们继承自一个常见的超类MasterDetailViewController。这个超类需要一些特定于设备的代码,因此我考虑对其进行子类化,然后以超类自动分配或实例化最适合的设备特定子类。
实施明智,如下所示:
+(id)allocWithZone:(NSZone *)zone {
if ([[self class] isEqual:[MasterDetailViewController_iPad class]] || [[self class] isEqual:[MasterDetailViewController_iPhone class]]) {
return [super allocWithZone:zone];
} else {
if ([[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {
return [MasterDetailViewController_iPhone allocWithZone:zone];
} else {
return [MasterDetailViewController_iPad allocWithZone:zone];
}
}
}
此代码不起作用,是一种概念演示。有没有办法做我想做的事情,或者我看错了什么?
编辑:为了清楚起见,超级和子类之间的数据是相同的。唯一的区别是几个方法实现。这个想法是子类化比设备特定的意大利面条代码更清晰。
答案 0 :(得分:1)
您的代码可能无法运行,因为类方法中的self
是类对象,因此[self class]
是类的类。请尝试[self isEqual:[MasterDetailViewController_iPad class]]
。您也可以转换比较,如下所示:
+ (id)allocWithZone:(NSZone *)zone {
// Allocating a subclass, don't interfere
if (![self isEqual:[MasterDetailViewController class]]) {
return [super allocWithZone:zone];
}
// Select an appropriate subclass to create instead
if ([[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {
return [MasterDetailViewController_iPhone allocWithZone:zone];
} else {
return [MasterDetailViewController_iPad allocWithZone:zone];
}
}
如果您有更多特定于设备的子类的原因,这可能会更容易扩展。
请注意,还有其他方法可以执行此操作。例如,一个通用类可以分配和使用特定于设备的辅助对象来处理需要不同的少数操作(有点像委托),而不是特定于设备的子类。或者,不是重写allocWithZone:,而是可以使用基类的init
方法版本self
,而是分配并返回相应子类的新对象。或者您可以使用工厂方法来分配适当的特定于设备的子类。