为什么从sharedInstance返回id

时间:2015-08-11 00:20:37

标签: objective-c singleton

sharedInstance模式的许多示例都返回一个id:

+ (id)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

而不是类实例:

+ (MyClass*)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

这是为什么?一个人一定比另一个好吗?

2 个答案:

答案 0 :(得分:3)

是的,从设计和可维护性的角度来看,返回idinstancetype或特定类之间存在重大差异。

id:是最老的一群。除非在+alloc-init系列的方法中使用它,否则类型推断将被禁止,并且假定返回的对象具有任何类型。它通常由编译器隐式地转换为您在声明中使用的任何具体类型。 init - 通过使用allocnew为您的方法名称添加前缀,并使用autorelease前缀方法名称,可以使用类方法恢复家庭式推理, initretainself

instancetype:是一个新人,授予-init - 家庭式的类型推理方法与"相关"返回类型(与他们所关注的类相关)。它通过将这些语义赋予任何标记为返回类型的方法来放宽推理命名限制id。一般来说,最好是id,因为你可以恢复更多的安全性(或者至少得到更好的警告)关于id限制未涵盖的某些方法的错误使用。

一个类:只有当你绝对确定你所售的实例没有特定的子类型或希望隐藏它的事实时才应该使用它。它对于UIColor等类集群或不应具有UIPasteboard等子类型的具体类非常有用。因此,它通常用作从特定类继承不安全的标记。

tl; dr如果您希望阻止子类化,那么请具体,否则instancetype

答案 1 :(得分:2)

CodaFi清楚地阐明(+1)基本id vs instancetype与明确的返回类型问题。

但我认为值得注意的是,单身人士sharedInstance方法为讨论添加了一个独特的皱纹:id和/或{{1}的整个想法是让子类更容易。但是,在单例的构造函数方法的上下文中,这并没有多大意义。

让我们假设您有一些代码库,其中您对某些基类有一些instancetype单例方法。并且让我们说在稍后的某个时候,你决定继承这个类,但忽略为子类实现一个新的sharedInstance。因此,您将使用单个sharedInstance静态继承相同的基类实现。如果您使用sharedInstance,编译器甚至会让您相信instancetype将返回子类的共享实例。

问题在于,如果在子类上调用[SubClass sharedInstance],您实际上无法确定您将获得哪种类型的对象。如果你不小心有一些旧代码在基类上调用它,那么从sharedInstance返回的对象可能是一个基类的实例!但是,如果您足够幸运地记得删除对项目中其他位置的基类[SubClass sharedInstance]方法的任何引用,那么您将正确地接收子类的实例。显然,这不是一个理想的情况,这个继承方法的行为可能会根据它在代码中的其他地方首次调用的方式而改变。这与单身人士的概念是对立的。

底线,虽然通常建议使用返回sharedInstance的遗留方法(或者,在过去的日子里,instancetype)使类可扩展,在单例的情况下,我通常不会就id方法提出建议。它错误地暗示了一种在这种情况下并不适用的可扩展性。

相反,我会建议(a)用sharedInstance方法让它返回显式数据类型; (b)如果您对代码进行子类化,则在子类上实现新的sharedInstance。这消除了歧义。