init方法返回不同类型的对象是否可接受?

时间:2012-03-15 18:49:45

标签: objective-c xcode

我正在处理一些现有的Objective-c代码的错误修正,并遇到了一些我认为奇怪的事情:

@interface ClassA : UIView
...

static ClassA* oldSelf = nil;

@implementation
- (id)initWithFrame:(CGRect)frame {
    oldSelf = self;
    self = [[ClassB alloc] initWithFrame:(CGRect)frame]; // xcode warns: Incompatible pointer types assigning to "ClassA *" from "ClassB *"
    //       ^^^^^^ Is this ok?
    [oldSelf release];
    return self;
}


@interface ClassB : UIView
...

@implementation
- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    return self;
}

这一切都包含在静态库中。公共获取lib.a文件和ClassA.h 在使用该库的代码中,会发生以下情况:

#import "ClassA.h"

...

// useage
ClassA *myA = [[ClassA alloc] initiWithFrame:CGRectMake(0,0,100,100)];
...

所以我们得到了ClassA的初始化器,它实际上返回了一个不相关的类。 ClassA和ClassB响应相同的消息,因此它编译并运行。似乎ClassA被用来掩盖ClassB中暴露的一些功能?

我很好奇这是否是可接受的行为,如果它是一个已知的模式,它叫什么?这个设置有副作用吗?

=============================================== ==========

感谢大家的回答!我想我已经得到了......简而言之,不是正常的模式,也不是一个好主意

  • 有点像“类集群”(抽象工厂),但并不完全,因为应该返回一个共同的抽象类。而且由于代码似乎并不打算返回除ClassB对象之外的任何内容,可能不是原作者所想的。
  • 更像是代理,但实施错误。 ClassA应该拥有ClassB的私有实例,并在两者之间传递消息。

=============================================== ==========

编辑:添加“oldSelf”部分......

已编辑:添加了静态库详细信息...

已编辑:添加了关于已接受答案的简介......

7 个答案:

答案 0 :(得分:3)

我在这里看到的主要缺点是:ClassA的用户希望他刚刚通过[[ClassA alloc] initWithFrame:...]创建的对象为[object isKindOfClass:[ClassA class]返回YES。 使用NSInvocation之类的东西时,这也可能导致错误,因为错误的类将用于确定方法签名,但我不确定。

由于Objective-Cs的动态特性,正如您所描述的那样,这将起作用,但可能会让人感到困惑,我强烈反对任何人使用这种模式。

正如pilavdzice所说,“right”的替代方案是让ClassAClassB继承自另一个类( abstact超类)然后在其初始化程序中决定使用什么具体子类。这种模式的好例子,称为类集群,是NSStringNSArrayNSDictionary,它们都根据你初始化它们的方式返回各种子类的对象,这也是你不能的原因直接将这些直接子类化。

答案 1 :(得分:3)

在所有情况下这都不是不合理的事情,但很难说在你描述的情况下这是否是个好主意。可能没问题的两个例子:

  • 初始值设定项返回更专业的子类的实例。例如,您可以根据存储的项目数选择不同的数据结构实现。

  • 初始化程序返回某种代理对象。

您的代码确实有点奇怪。至少,我希望看到一个演员作为一个信号(编译器和未来的程序员),作者知道他在做什么。解释返回不同类型对象的原因的评论也不会受到影响。理想情况下,ClassB应该是ClassA的子类,因为它应该提供相同的接口。

答案 2 :(得分:2)

类集群以这种方式实现,排序。相关技术isa - 调配可用于实现某种状态机。它确实需要相同的ivar布局才能工作。在副作用方面,我认为它可能打破KVO;但有人可能会纠正我。

答案 3 :(得分:1)

在用户代码中返回不相关的类肯定不常见,但在Apple的某些框架中,通常使用相同的公共接口返回更具体版本的类。

Apple的 Cocoa Fundamentals详细讨论了NSArray和NSNumber等对象可能返回与您要求的类不同的对象这一事实。

答案 4 :(得分:0)

这不是我所知道的模式。

如果我正确地理解了这一点,那么通常的方法是让两个类都从相同的抽象基类继承。

答案 5 :(得分:0)

正如@alan duncun所说,这种技术被称为类集群,并且有些常见。但是你的实现有点不正确。您永远不应该返回不兼容的类型。在您的示例中,ClassB应该继承自ClassA。

答案 6 :(得分:0)

这有点像NSScanner的实施方式。

这样,内部类不会暴露,也不会被滥用。除了ClassA的实现文件之外,ClassB不能在其他地方初始化。

如果您有多个内部类并且初始化程序以某种方式决定实际需要哪个类,这是有道理的。

如果你只使用一个内部类,我认为没有任何好处。