为什么在类方法BAD中"self = [[Rectangle alloc] init]"?

Pro*_*ton 8 cocoa objective-c class-method

在Apple的"Objective-C Programming Language"文档中,第48页说:

+ (Rectangle *)rectangleOfColor:(NSColor *) color
{
    self = [[Rectangle alloc] init]; // BAD
    [self setColor:color];
    return self;
}

+ (id)rectangleOfColor:(NSColor *)color
{
     id newInstance = [[Rectangle alloc] init]; // GOOD
     [newInstance setColor:color];
     return newInstance;
}


+ (id)rectangleOfColor:(NSColor *)color
{
     id newInstance = [[self alloc] init]; // EXCELLENT
     [newInstance setColor:color];
     return newInstance;
}
Run Code Online (Sandbox Code Playgroud)

一个是坏的,一个是好的,另一个是优秀的.这是为什么?

bbu*_*bum 17

还有第四种模式......

(1)类型不匹配是BAD.

(2)静态引用类产生的方法在子类中不能正常运行

(3)对类的动态引用意味着子类将被实例化为子类实例


(4)

+ (instancetype)rectangleOfColor:(NSColor *)color // Über-bestest evar!
{
     Rectangle *newInstance = [[self alloc] init];
     [newInstance setColor:color];
     return newInstance;
}
Run Code Online (Sandbox Code Playgroud)

llvm添加了一个instancetype关键字"yo!this method返回它所调用的任何类的实例".因此,如果你是上面的子类,你可以:

RectangleSub *rs = [RectangleSub rectangleOfColor:[NSColor paisleyColor]];
Run Code Online (Sandbox Code Playgroud)

但这会警告(超出可怕的颜色选择):

RectangleSub *rs = [Rectangle rectangleOfColor:[NSColor puceColor]];
Run Code Online (Sandbox Code Playgroud)

而(id)返回类型在第二种情况下不会发出警告.

请注意,我也切换声明newInstance为明确的类型Rectangle*.这是越多越好,太多,在该方法的范围内,newInstance只能安全地处理过Rectangle*.

  • 谢谢你的编辑.它是最近版本的LLVM的新特性.NSHipster有一篇很好的文章:http://nshipster.com/instancetype/ (4认同)

Vik*_*ica 9

+ (Rectangle *)rectangleOfColor:(NSColor *) color
{
    self = [[Rectangle alloc] init]; // BAD
    [self setColor:color];
    return self;
}
Run Code Online (Sandbox Code Playgroud)

在类方法中self引用类,而不是它的实例对象.


+ (id)rectangleOfColor:(NSColor *)color
{
    id newInstance = [[Rectangle alloc] init]; // GOOD
    [newInstance setColor:color];
    return newInstance;
}
Run Code Online (Sandbox Code Playgroud)

如果Rectangle将被子类化(MyFancyRectangle),那么仍然会返回一个普通的Rectangle对象

+ (id)rectangleOfColor:(NSColor *)color
{
    id newInstance = [[self alloc] init]; // EXCELLENT
    [newInstance setColor:color];
    return newInstance;
}
Run Code Online (Sandbox Code Playgroud)

会返回一个MyFancyReactangleif if like MyFancyReactangle *r = [MyFancyReactangle rectangleOfColor:[UIColor redColor]],就像[self alloc]在子类上调用一样.注意,这里self再次调用类,+alloc类方法也是如此.

出于同样的原因,所有init…方便的创建者方法都应该返回id.它允许子类返回子类的对象,而不会让编译器发疯.


Car*_*zey 6

在第一种情况下,将self指针(应指向Rectangle类对象)分配给实例Rectangle.这绝对不正确.

在第二种情况下,您需要对要实例化的类进行硬编码 - Rectangle在本例中.

在第三种情况下,您允许类的标识来确定实例的类,而不是在代码中明确指定它.然后,如果您的Dodecahedron类需要使用相同的代码,则不需要更改类名.