如何避免重复的代码目标-c

时间:2012-06-19 12:16:49

标签: objective-c ios oop

我有两种不同的方式在我的应用中表示数据:通过UITableViewUIScrollView
所以我有两个主要类:AppTableView: UITableViewAppScrollView: UIScrollView。 我想对两个视图实现相同的添加。所以我写了两个类:SomeAdditionsTableView: UITableViewSomeAdditionsScrollView: UIScrollView。这个类的代码是一样的。 主要课程现在看起来像 AppTableView: SomeAdditionsTableViewAppScrollView: SomeAdditionsScrollView

如何避免此代码重复?提前致谢。

3 个答案:

答案 0 :(得分:4)

是的,这是Objective-c中缺少多重继承的问题。当我在UIView和UIScrollView的子类上需要某些方法时,我遇到了同样的问题:Subclassing UIView vs UIScrollView。我知道有三种可能的解决方案:

  1. 如果您不需要存储任何类型的实例变量,只需在UIScrollView上声明一个类别,并确保将该类别导入到两个子类中。这是最简单的解决方案,但最不可能工作,因为如果你是子类,你可能需要存储状态信息。
  2. 只创建UITableView的子类,当你不想要UITableView时,根本不要将它用作UITableView。从技术上讲,您可以将UITableView用作UIScrollView,而无需调用任何tableView的方法。当然,你最终将携带tableView(它的所有实例变量)的'权重',但没有理由你必须使用UITableView作为UITableView而不仅仅是UIScrollView。
  3. 将尽可能多的代码委托给单独的对象,以最大限度地减少代码重复。在每个单独的子类中,携带一个实例变量,即方法委托和转发方法调用该委托。现在,这里变得有趣。您可以使用协议在子类中声明委托方法并覆盖特殊的NSObject方法:- (id) forwardingTargetForSelector:(SEL)aSelector以确保将这些方法调用发送给委托。您在子类上使用符合委托类中声明的协议的类别。这将公开子类中委托类的所有方法,而不要求您在子类中实际实现这些方法。当运行时无法在子类中找到声明的方法时,它将调用- (id) forwardingTargetForSelector:(SEL)aSelector,您可以使用它来返回您的委托/转发类。这将阻止您需要转发每个单独的方法。根据这些方法调用的内容,这可能需要更多的“连接”,但它最终会为您节省大量代码。它基本上“模仿”使用协议的objective-c中的多重继承。有关详情,请参阅我的问题/答案:https://stackoverflow.com/a/9419587/1147934
  4. 在这三个中,最后一个选项对我来说是最好的选择。需要做一些工作才能解决问题,但会显着减少代码重复。当我想要子类化而没有子类化时,我也使用它。但是,最大的要求是你想要做的任何类都必须将它的方法声明从它的接口移到一个单独的协议中。但这真的不是什么大不了的事,并且获得“像行为这样的多重继承”的好处是很棒的。

    此外,有时您可能需要转发的类来访问转发类(子类)中的实例变量。您可以通过使用委托模式来实现此目的,其中转发的类维护对转发类的弱引用,以便访问这些实例变量。例如,在您的情况下,如果您尝试委派在UIScrollView上运行的方法,那么这些方法可能需要能够访问该视图。如果这些方法停留在委托类中,除非您将它们提供给它们,否则它们将无法直接访问视图的变量。与通常的任何委托模式一样,要非常小心,不要创建保留周期。

答案 1 :(得分:0)

如果您的添加内容不需要任何自己的状态,则可以在UIScrollView上将其设为category。然后,由于UITableViewUIScrollView的类型,您也可以在其中一个上使用类别方法。

如果他们确实需要定义新的变量,那么我会把它变成一个独立的类,并且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];