Swift调用静态方法:type(of:self)vs explicit class name

Ori*_*rds 26 static-methods swift

在swift中,如果没有使用类名称为方法调用添加前缀,则实例func不能调用a static/class func.或者你可以使用type(of: self),例如

class Foo {
    static func doIt() { }

    func callIt() {
        Foo.doIt() // This works
        type(of: self).doIt() // Or this

        doIt() // This doesn't compile (unresolved identifier)
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,这有什么区别?它只是编码风格的问题,还是存在一些差异,例如静态或动态调度?

如果它只是编码风格,那么首选的风格是什么?

Ham*_*ish 31

主要有两个不同之处.

1. self静态方法内部的值

您在方法中可以使用您调用静态方法的元类型self(它只是作为隐式参数传递).因此,如果你打电话doIt()type(of: self),self将是动态的实例元类型.如果你调用它Foo,self将是Foo.self.

class Foo {
    static func doIt() {
        print("hey I'm of type \(self)")
    }

    func callDoItOnDynamicType() {
        type(of: self).doIt() // call on the dynamic metatype of the instance.
    }

    func classDoItOnFoo() {
        Foo.doIt() // call on the metatype Foo.self.
    }
}

class Bar : Foo {}

let f: Foo = Bar()

f.callDoItOnDynamicType() // hey I'm of type Bar
f.classDoItOnFoo()        // hey I'm of type Foo
Run Code Online (Sandbox Code Playgroud)

这种差异对于工厂方法非常重要,因为它决定了您创建的实例的类型.

class Foo {
    required init() {}

    static func create() -> Self {
        return self.init()
    }

    func createDynamic() -> Foo {
        return type(of: self).create()
    }

    func createFoo() -> Foo {
        return Foo.create()
    }
}

class Bar : Foo {}

let f: Foo = Bar()

print(f.createDynamic()) // Bar
print(f.createFoo())     // Foo
Run Code Online (Sandbox Code Playgroud)

2.调度静态方法

(马丁已经介绍了这一点,但我想我会为了完成而添加它.)

对于class在子类中重写的方法,您调用方法的元类型的值确定要调用的实现.

如果调用在编译时已知的元类型(例如Foo.doIt()),则Swift能够静态地调度该调用.但是,如果在运行时(例如type(of: self))之前调用的元类型上调用方法,则会将方法调用动态调度到元类型值的正确实现.

class Foo {
    class func doIt() {
        print("Foo's doIt")
    }

    func callDoItOnDynamicType() {
        type(of: self).doIt() // the call to doIt() will be dynamically dispatched.
    }

    func classDoItOnFoo() {
        Foo.doIt() // will be statically dispatched.
    }
}


class Bar : Foo {
    override class func doIt() {
        print("Bar's doIt")
    }
}

let f: Foo = Bar()

f.callDoItOnDynamicType() // Bar's doIt
f.classDoItOnFoo()        // Foo's doIt
Run Code Online (Sandbox Code Playgroud)