我有两种不同的方式在我的应用中表示数据:通过UITableView
或UIScrollView
。
所以我有两个主要类:AppTableView: UITableView
和AppScrollView: UIScrollView
。
我想对两个视图实现相同的添加。所以我写了两个类:SomeAdditionsTableView: UITableView
和SomeAdditionsScrollView: UIScrollView
。这个类的代码是一样的。
主要课程现在看起来像
AppTableView: SomeAdditionsTableView
和AppScrollView: SomeAdditionsScrollView
。
如何避免此代码重复?提前致谢。
答案 0 :(得分:4)
是的,这是Objective-c中缺少多重继承的问题。当我在UIView和UIScrollView的子类上需要某些方法时,我遇到了同样的问题:Subclassing UIView vs UIScrollView。我知道有三种可能的解决方案:
- (id) forwardingTargetForSelector:(SEL)aSelector
以确保将这些方法调用发送给委托。您在子类上使用符合委托类中声明的协议的类别。这将公开子类中委托类的所有方法,而不要求您在子类中实际实现这些方法。当运行时无法在子类中找到声明的方法时,它将调用- (id) forwardingTargetForSelector:(SEL)aSelector
,您可以使用它来返回您的委托/转发类。这将阻止您需要转发每个单独的方法。根据这些方法调用的内容,这可能需要更多的“连接”,但它最终会为您节省大量代码。它基本上“模仿”使用协议的objective-c中的多重继承。有关详情,请参阅我的问题/答案:https://stackoverflow.com/a/9419587/1147934。在这三个中,最后一个选项对我来说是最好的选择。需要做一些工作才能解决问题,但会显着减少代码重复。当我想要子类化而没有子类化时,我也使用它。但是,最大的要求是你想要做的任何类都必须将它的方法声明从它的接口移到一个单独的协议中。但这真的不是什么大不了的事,并且获得“像行为这样的多重继承”的好处是很棒的。
此外,有时您可能需要转发的类来访问转发类(子类)中的实例变量。您可以通过使用委托模式来实现此目的,其中转发的类维护对转发类的弱引用,以便访问这些实例变量。例如,在您的情况下,如果您尝试委派在UIScrollView上运行的方法,那么这些方法可能需要能够访问该视图。如果这些方法停留在委托类中,除非您将它们提供给它们,否则它们将无法直接访问视图的变量。与通常的任何委托模式一样,要非常小心,不要创建保留周期。
答案 1 :(得分:0)
如果您的添加内容不需要任何自己的状态,则可以在UIScrollView
上将其设为category。然后,由于UITableView
是UIScrollView
的类型,您也可以在其中一个上使用类别方法。
如果他们确实需要定义新的变量,那么我会把它变成一个独立的类,并且MyTableView : UITableView
子类具有SomeAdditions
属性,类似地,MyScrollView : UIScrollView
。
答案 2 :(得分:0)
你可以通过使用协议和“has_a” - 关系来实现很多目标,而不是继承的“is_a” - 关系。 一种非常常见的模式是委托,但协议对于将方法调用转发到封装或包装对象也很有用 在下面的示例中,彼此不相关的类共享一个公共对象,但同样类型的对象也可能使用不同类的对象,这些对象都实现了一个共同的协议,所以相同的对象可以做非常不同的东西。
@interface ClassA : NSObject
@property (strong) id<BrainProtocol> *brain
@end
@@implementation ClassA
@synthezise brain;
-(void)theMethod
{
[brain theMethod];
}
@end
@interface ClassB : NSObject
@property (strong) id<BrainProtocol> *brain
@end
@@implementation ClassB
@synthezise brain;
-(void)theMethod
{
[brain theMethod];
}
@end
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
//A object, that implements the BrainProtocol
Brain *brain = [[brain alloc] init];
[a setBrain:brain];
[b setBrain:brain];