Когда мы используем Any в Swift? Какая разница между Any и AnyObject? Чем они могут быть полезны? В сегодняшней статье я отвечу на эти вопросы.
Что из себя представляет Any?
Язык программирования Swift предоставляет нам два особых типа: Any и AnyObject. Они неспецифичны, потому что они могут быть чем угодно.
Рассмотрим пример:
let age: Int = 42
Данный тип Int является конкретным. age является целым числом.
Теперь давайте посмотрим на тип Any. Следующий код определяет массив values типа [Any]:
let values: [Any] = ["Apple", 99, "Zaphod", -1]
На первый взгляд данный код не имеет смысла. Как может массив содержать несколько разных типов, таких как Int и String? Это возможно потому, что тип данного массива неспецифичен, то есть он имеет тип [Any].
При этом отдельные элементы массива values используют свои собственные специфические типы:
let values: [Any] = ["Apple", 99, "Zaphod", -1] for value in values { switch value { case is String: print("\(value) имеет тип String!") case is Int: print("\(value) имеет тип Int!") default: print("Неизвестный тип!") } } // Apple имеет тип String! // 99 имеет тип Int! // Zaphod имеет тип String! // -1 имеет тип Int!
В приведенном выше примере мы используем цикл for для перебора элементов в массиве values. Далее мы проверяем тип каждого элемента с помощью switch.
- Тип массива values имеет неспецифический тип или [Any].
- Типы отдельных элементов массива являются конкретными типами, такими как Int и String.
Зачем использовать Any и AnyObject?
В Swift есть несколько аспектов в программировании, которые делают работу с типами более гибкой:
- Опционалы позволяют эффективно работать со значениями, которые могут иметь или не иметь значения.
- Дженерики помогают нам создавать заполнители, которые могут работать с разными типами.
- Протоколы помогают определять ограничения для определенных типов, независимо от того, какой тип принимает.
Опционалы, дженерики, протоколы, приведение типов, Any и AnyObject – все эти инструменты помогают нам более эффективно обрабатывать данные. Они делают наш код более понятным и выразительным, позволяя легче его расширять и поддерживать.
Any и AnyObject особенно полезны для значений, которые имеют смешанные неспецифические типы.
let tweet: [String: Any] = [ "text": "Lorem ipsum dolor amet hoodie bicycle rights, 8-bit mixtape", "likes": 42, "retweets": ["@alex42", "@aplusk", "@beeblebrox"] ]
Созданный нами словарь смешивает значения разных типов. Первое значение – это String, второе – Int, а третье – [String].
Что делать, если мы хотим получить конкретное значение в словаре tweet?
if let likes = tweet["likes"] { print("У этого твита \(likes) лайков!") }
В приведенном выше коде константа likes имеет тип Int. Мы используем опциональное связывание для получения значения по его ключу. При необходимости вы также можете сделать явное приведение типа:
if let likes = tweet["like"] as? Int { ...
Благодаря типу Any мы можем объединить разные значения в одном словаре. При этом нам не нужно создавать отдельный класс или тип для твита.
Разница между Any и AnyObject
- Any может представлять экземпляр любого типа, включая типы функций.
- AnyObject может представлять экземпляр любого типа класса.
Мы используете Any для всего, а AnyObject только для классов. Но это еще не все.
Во-первых, важно понимать разницу между значимыми типами и ссылочными типами. В значимом типе значение копируется, когда вы передаете его в свой код, а в ссылочном типе нет. Классы являются ссылочными типами, и передача их в вашем коде просто создает ссылку на исходный объект.
Во-вторых, важно понимать роль Objective-C, предшественника Swift. В Objective-C вы можете использовать полиморфный нетипизированный id указатель для ссылки на любой тип объекта, что очень похоже на Any и AnyObject в Swift.
В Objective-C все объекты являются ссылочными типами. Доступ к ним осуществляется через указатели, и в Objective-C отсутствует концепция значимого типа.
Одной из особенностей Swift является его совместимость с Objective-C. Вы можете использовать код Objective-C в коде на Swift и наоборот. И вы можете использовать SDK, написанные на Objective-C, в ваших проектах на Swift.
Эта совместимость зависит, помимо прочего, от связывания типов Swift и типов Objective-C. Тип NSString, например связан с типом Swift String. В результате вы можете легко работать со строками между двумя языками.
Помните, что AnyObject может работать только с классами? Это подразумевает, что AnyObject – это ссылочный тип. Objective-C не имеет значимых типов и id является ссылочным типом, потому что он использует указатели. И это имеет огромный недостаток: вы не можете извлечь выгоду из значимых типов Swift при взаимодействии с Objective-C id. Поэтому Objective-C id импортируется как Any в Swift.
Когда вы должны выбрать один тип или другой? Хорошей практикой будет использовать AnyObject при работе с классами и Any при работе со значимыми типами.
Как мы видели в предыдущих примерах, для массива с целыми числами и строками следует использовать Any, потому что они являются значимыми типами. Вы можете использовать Any с классами, но лучше использовать AnyObject.