Ответ 1
Существуют два основных отличия.
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
Это различие может быть действительно важным для методов factory, поскольку оно определяет тип создаваемого экземпляра.
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
2. Отправка статического метода
(Мартин уже рассмотрел это, но я думал, что добавлю его ради завершения.)
Для class
методов, переопределенных в подклассах, значение метатипа, вызываемого методом, определяет, какую реализацию вызывать.
Если вызывается в метатипе, который известен во время компиляции (например, Foo.doIt()
), Swift может статически отправлять вызов. Однако, если вы вызываете метод по метатипу, который неизвестен до времени выполнения (например, type(of: self)
), вызов метода будет динамически отправляться в правильную реализацию для значения метатипа.
class Foo {
class func doIt() {
print("Foo 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 doIt")
}
}
let f: Foo = Bar()
f.callDoItOnDynamicType() // Bar doIt
f.classDoItOnFoo() // Foo doIt