Какая разница между метатипом .Type и .self в Swift?
Do .self и .Type вернуть a struct?
Я понимаю, что .self можно использовать для проверки с помощью dynamicType. Как вы используете .Type?
Какая разница между метатипом .Type и .self в Swift?
Do .self и .Type вернуть a struct?
Я понимаю, что .self можно использовать для проверки с помощью dynamicType. Как вы используете .Type?
Вот быстрый пример:
func printType<T>(of type: T.Type) {
// or you could do "\(T.self)" directly and
// replace 'type' parameter with an underscore
print("\(type)")
}
printType(of: Int.self) // this should print Swift.Int
func printInstanceDescription<T>(of instance: T) {
print("\(instance)")
}
printInstanceDescription(of: 42) // this should print 42
Допустим, каждая сущность представлена двумя вещами:
Тип: # entitiy name #
Метатип: # entity name #.Type
Тип метатипа относится к типу любого типа, включая типы классов, типы структур, типы перечисления и типы протоколов.
Вы можете быстро заметить, что это рекурсивно и может быть с помощью таких типов, как (((T.Type).Type).Type) и так далее.
.Type возвращает экземпляр метатипа.
Есть два способа получить экземпляр метатипа:
Вызовите .self для конкретного типа, такого как Int.self который создаст статический экземпляр Int.Type.
Получить экземпляр динамического метатипа из любого экземпляра через type(of: someInstance).
Опасная зона:
struct S {}
protocol P {}
print("\(type(of: S.self))") // S.Type
print("\(type(of: S.Type.self))") // S.Type.Type
print("\(type(of: P.self))") // P.Protocol
print("\(type(of: P.Type.self))") // P.Type.Protocol
.Protocol является еще одним метатипом, который существует только в контексте протоколов. Тем не менее, нет никакого способа, как мы можем выразить, что мы хотим только P.Type. Это предотвращает работу всех общих алгоритмов с метатипами протоколов и может привести к сбоям во время выполнения.
Для более любопытных людей:
Функция type(of:) фактически обрабатывается компилятором из-за несоответствия, .Protocol.
// This implementation is never used, since calls to 'Swift.type(of:)' are
// resolved as a special case by the type checker.
public func type<T, Metatype>(of value: T) -> Metatype { ... }
Где это используется?
Если вы пишете/создаете функцию, которая принимает тип, например, UIView.Type, а не экземпляр, например, UIView() тогда вам следует написать T.Type в качестве типа параметра. То, что он ожидает в качестве параметра, может быть: String.self, CustomTableView.self, someOtherClass.self.
Обычно функция, для которой требуется тип, - это функция, которая создает для вас объекты. Я могу вспомнить два хороших примера:
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
Обратите внимание, что вы передали CustomTableViewCell.self. Если позже вы попытаетесь удалить из таблицы tableView типа CustomTableViewCell но не зарегистрируете тип CustomTableViewCell то произойдет сбой, потому что tableView не удалил из очереди/не создал ни одного элемента viewview ячейки типа CustomTableViewCell.
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
let json = """
{
"name": "Durian",
"points": 600,
"description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
print(product.name)
Обратите внимание, try decoder.decode(GroceryProduct.self, from: json). Поскольку вы передали GroceryProduct.self он знает, что ему нужно создать экземпляр объекта типа GroceryProduct. Если он не может, то выдает ошибку
Подробнее о внутренностях и как это работает:
Метатип класса, структуры или типа перечисления - это имя этого типа, за которым следует .Type. Метатип типа протокола, а не конкретный тип, который соответствует протоколу во время выполнения, - это имя этого протокола, за которым следует .Protocol. Например, метатипом типа класса
SomeClassявляетсяSomeClass.Typeа метатипом протоколаSomeProtocolявляетсяSomeProtocol.Protocol.От Apple: тип мета-типа
Под капотом AnyClass есть
typealias AnyClass = AnyObject.Type // which is why you see T.Type
В основном AnyClass, где вы видите AnyClass, Any.Type, AnyObject.Type, потому что он нуждается в типе. Очень распространенное место, которое мы видим, это когда мы хотим зарегистрировать класс для нашего tableView, используя register func.
func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)
Если вы не уверены, что означает "Свифт".сделай тогда выше, потом посмотри комментарии отсюда
Вышесказанное также можно записать так:
func register(_ cellClass: AnyObject.Type, forCellReuseIdentifier identifier: String)
Вы можете использовать самовыражение postfix для доступа к типу в качестве значения. Например, SomeClass.self возвращает сам SomeClass, а не экземпляр SomeClass. И SomeProtocol.self возвращает сам SomeProtocol, а не экземпляр типа, который соответствует SomeProtocol во время выполнения. Вы можете использовать выражение типа (of :) с экземпляром типа для доступа к динамическим типам экземпляров в качестве значения, как показано в следующем примере:
От Apple: тип мета-типа
Код детской площадки:
Простой пример
struct Something {
var x = 5
}
let a = Something()
type(of:a) == Something.self // true
Тяжелый пример
class BaseClass {
class func printClassName() {
print("BaseClass")
}
}
class SubClass: BaseClass {
override class func printClassName() {
print("SubClass")
}
}
let someInstance: BaseClass = SubClass()
/* | |
compileTime Runtime
| |
To extract, use: .self type(of)
The compile-time type of someInstance is BaseClass,
and the runtime type of someInstance is SubClass */
type(of: someInstance) == SubClass.self // TRUE
type(of: someInstance) == BaseClass.self // FALSE
Я настоятельно рекомендую прочитать документацию Apple по типам. Также смотрите здесь
Они появляются в разных местах синтаксически.
В синтаксическом месте, где вам нужно указать тип, Something.Type является допустимым типом, соответствующим типу, который является метатипом (который является метаклассом для классов) Something. Something.self не является допустимым синтаксисом для типа.
В синтаксическом месте, где вам нужно написать выражение, Something.self является допустимым выражением. Это выражение типа Something.Type, а значение - это вещь ( "объект класса" в случае классов), которая представляет тип Something. Something.Type не является допустимым синтаксисом выражения.