我有以下情况:
我正在延长UITextView control (MyTextView : UITextView)
。根据运行时设备版本,我有不同的实现。所以目前我在MyTextView
类的实现中有很多“if-else”语句。
为了使其更易于维护,我想将其拆分为不同的类:
MyTextViewIos5 : MyTextView
,MyTextViewIos6:MyTextView
和创建一个工厂函数,它将在运行时知道根据设备iOS版本创建哪个子类。
如果我使用MyTextView作为参数,此解决方案可以正常工作。
MyTextView* textView = [Factory createWithFrame:frame];
当有一个继承自MyTextView (externalTextView:MyTextView)
的类并使用特定方法扩展它时,问题就开始了,
它的initWithFrame
方法将如下所示:
- (id)initWithFrame:(CGRect)frame {
self = [Factory createWithFrame:frame];
if (self) {
...
}
return self;
}
我没有打电话给超级initwithFrame
,而是打电话给我的工厂。
当我调用externalTextView
特定方法时,应用程序崩溃时出现错误, MyTextViewIos5 或 MyTextViewIos6 未实现调用的特定方法。
是否有解决方法使其正常工作?
答案 0 :(得分:1)
只需为self = [Factory createWithFrame:]
或MyTextViewIos5
而非自定义类的数据分配MyTextViewIos6
。因此,您的自定义类的方法表等不存在,这就是它崩溃的原因。
继承的本质是,您必须子类MyTextViewIos5
MyTextViewIos6
才能继承其功能。问题是你不知道哪个。
我建议将自定义类的功能分离为委托/协议设计。 MyTextView超类可以包含用于管理委托的代码。
类似的东西:
- (void)methodCustomSubclassWouldHaveOverridden
{
[delegate handleThisForMe];
}
答案 1 :(得分:0)
如果您定义一个类,则从MyTextView
派生的每个类都应在其自己的[super initWithFrame]
方法中调用initWithFrame
。如果您不需要对派生类实例进行任何自定义初始化,则可以完全省略init方法。
在一般情况下,您的工厂createWithFrame
应该是:
- (MyTextView*)createWithFrame:(CGRect)frame {
if (<iOS6>)
return [[MyTextViewOS6 alloc] initWithFrame];
if (<iOS5>)
...
}
现在,如果你的派生类不需要任何特殊的初始化,你可以简单地在每个类中保留initWIthFrame
方法(并且只在基类中定义一个)。
或者,您可以在工厂中进行初始化,如下所示:
- (MyTextView*)createWithFrame:(CGRect)frame {
if (<iOS6>)
MyTextViewOS6* view = [[MyTextViewOS6 alloc] initWithFrame];
view.iOS6SpecificProperty = ...;
[view iOS6SpecificMethod:...];
return view;
if (<iOS5>)
...
}
你在做什么:
self = [Factory createWithFrame:frame];
正在分配MyTextView
的新实例并替换self
原始值。换句话说,当你这样做时:
externalTextView* view = [[externalTextView alloc] initWithFrame];
首先为externalTextView
类型的对象分配内存;然后,调用该类的initWithFrame方法。现在,如果你在initWithFrame中执行:
self = [Factory createWithFrame:frame];
您正在通过工厂实例化一个新对象,并将指针指向self
(最初指向通过alloc创建的对象)。
希望这有帮助。