1

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

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

4

3 回答 3

4

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

  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 。

Of the three, the last option tends to work the best for me. It takes a little work to get your head around but will significantly reduce code duplication. I also use it when I want to subclass without subclassing. The biggest requirement, though, is any class that you want to do this with will have to move it's method declarations out of it's interface into a separate protocol. But it's really not a big deal and the benefits of getting 'multiple inheritance like behavior' is great.

Also, there are times you may need the forwarded class to access instance variables in the forwarding class (the subclass). You can achieve this by using a delegate pattern whereby the forwarded class maintains a weak reference to the forwarding class in order to access those instance variables. For example, in your case, if you're trying to delegate methods that operate on a UIScrollView, those methods may need to be able to access that view. If those methods are stuck in a delegate class, they won't have direct access to the view's variables unless you give it to them. As usual with any delegate pattern, be very careful you don't create a retain cycle.

于 2012-06-19T12:59:33.317 回答
0

如果您的添加不需要任何自己的状态,您可以将它们设置UIScrollView. 然后,由于 aUITableView是 的一种UIScrollView,您也可以在其中一个上使用类别方法。

如果他们确实需要定义新变量,那么我会将其设为一个独立的类,并拥有一个MyTableView : UITableView具有SomeAdditions属性的子类,类似地,MyScrollView : UIScrollView.

于 2012-06-19T12:25:59.883 回答
0

You can achieve a lot by using protocols and "has_a"-relationships, instead of inheritance's "is_a"-relationships.
One very common pattern is delegate, but protocols are also useful for forwarding methods calls to encapsulated or wrapped objects.
in the following example to classes, that are not related to each other, share a common object, but it is also possible, that objects of the same kind use objects of different classes, that all implement a common protocol, so equal objects could do very different stuff.

@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]; 
于 2012-06-19T14:01:19.223 回答