Any и AnyObject в Swift. В чем их различие?

Довольно долгое время в своих проектах при написании кода я использовал тип Any, например при обработке JSON данных. Но также я знал что есть и второй тип — AnyObject. И недавно я задумался о разнице между этими двумя типами.

Согласно документации Apple:

  • Any — может представлять экземпляр любого типа
  • AnyObject — может представлять экземпляр любого класса

Если сказать чуть проще, то:

  • Any используется для всех типов
  • AnyObject — используется для типов Class

Проверим на деле эти два типа. Начнем с типа Any

Для этого создадим массив с типом Any, и распечатаем его.

let anyArray: [Any] = ["Macbook", 1, 2] print(anyArray) Console: ["Macbook", 1, 2]

Как мы видим, Any позволяет работать с различными типами данных одновременно (String, Int).

Согласно документации, элементы (String и Int) в этом массиве являются структурами, которые являются типами значений, поэтому, теоретически, AnyObject не должен работать.

Чтобы проверить это, был создан идентичный массив, с типом AnyObject.

let anyObjectArray: [AnyObject] = ["Macbook", 1, 2]

Как и ожидалось, компилятор выдает нам ошибку о невозможности преобразовании типа «String/Int» к типу AnyObject

Cannot convert value of type «Int» to expected element type «AnyObject»

Cannot convert value of type «Int» to expected element type «AnyObject»

Cannot convert value of type "String" to expected element type "AnyObject"

Но давайте все таки попробуем привести три наших типа к AnyObject и распечатать результат.

let anyObjectArray: [AnyObject] = ["Macbook" as AnyObject, 1 as AnyObject, 2 as AnyObject] print(anyObjectArray) Console: [Macbook, 1, 2]

Ошибка компилятора исчезла. Как мы видим, строка Macbook явно выглядит как строка, но не имеет привычных кавычек как у типа String в Swift.

Попробуем распечатать массив с помощью цикла, чтобы проверить их фактический тип.

for item in anyObjectArray { if item is String { print("\(item) является типом String") } else if item is Int { print("\(item) является типом Int") } } Console: Macbook является типом String 1 является типом Int 2 является типом Int

Строка имеет тип String. Как было сказано раньше, строки в Swift являются структурами, а не типами классов. Значит, мы не должны иметь возможность использовать их как AnyObject.

Проведем еще пару экспериментов с нашим массивом. Попробуем проверить их на типы из Objective‑C: NSString и NSNumber.

for item in anyObjectArray { if item is NSString { print("\(item) является типом NSString") } else if item is NSNumber { print("\(item) является типом NSNumber") } } Console: Macbook является типом NSString 1 является типом NSNumber 2 является типом NSNumber

Строка является NSString, а числовой элемент является NSNumber. И оба этих типа являются ссылочными в Objective‑C.

Так почему такое происходит?

Как часть своей совместимости с Objective‑C, Swift предлагает удобные и эффективные способы работы с платформами Cocoa.

Swift автоматически преобразует некоторые типы Objective‑C в типы Swift, а некоторые типы Swift в типы Objective‑C. Типы, которые можно конвертировать между Objective‑C и Swift, называются соединенными.

Другими словами, компилятор делает все возможное, чтобы быть гибким в обработке таких типов посредством автоматического преобразования и создания «мостов», в то же время предотвращая сбои приложения.

Когда же использовать AnyObject?

Как говорится в документации Apple, AnyObject может быть использован для работы с объектами, которые являются производными от Class, но не имеют общего корневого класса.

В Swift 3 тип id в Objective‑C теперь отображается на тип Any в Swift, который описывает значение любого типа, будь то класс, перечисление, структура или любой другой тип Swift. Это изменение делает API-интерфейсы Objective‑C более гибкими в Swift, поскольку определяемые Swift типы значений могут передаваться в Objective‑C API-интерфейсы и извлекаться как типы Swift, что устраняет необходимость в ручных «блочных» типах.

Таким образом, AnyObject желательно использовать когда вы хотите ограничить протокол, чтобы его можно было использовать лишь с классами, а Any в остальных случаях.

Используйте Any и AnyObject только тогда, когда вам явно нужно поведение и возможности, которые они предоставляют. Всегда лучше быть точным в отношении типов, которые вы ожидаете использовать в своем коде.

Спасибо за чтение, надеюсь что этот пост помог вам разобраться в чем разница между Any и AnyObject.

0
7 комментариев
Написать комментарий...
Bucky Bucks

На vc.ru остались одни юные программисты?(учитывая что у статьи положительный рейтинг, а тема статьи это основы основ и есть в любом простом учебнике или документации)

.
Я тоже отношусь к программистам, но все же тематика у vc совсем другая, поэтому ставлю жирный downvote. 

Ответить
Развернуть ветку
Francis R. Wilkeу

То есть если бы это была статья для продвинутых, то это бы подошло под тематику vc? :)
Автору спасибо.

Ответить
Развернуть ветку
Bucky Bucks

нет. vc вообще не про код, помимо этого статья абсолютно не несет смысловой нагрузки 

Ответить
Развернуть ветку
Akylbek Utekeshev
Автор

Разработка

 Сообщество разработчиков: публикации о личном опыте, выдающиеся приемы при решении рутинных задач, полезные материалы для профессионального роста.

В общем, классический мир разработки, системного администрирования и QA.

Тогда про что же ещё vc.ru и подраздел Разработка? 

Ответить
Развернуть ветку
Pavel Anpleenko

В общем нужно спользовать Any и спать спокойно

Ответить
Развернуть ветку
Кещик Щепещек

Так а в чем разница
protocol A: class
protocol B: AnyObject
?

Ответить
Развернуть ветку
Akylbek Utekeshev
Автор

Разницы между class'ом и AnyObject'ом нет никакой. Вы можете использовать и то, и другое) Если вы откроете Xcode, найдете какой-нибудь протокол с одним из этих типов, и посмотрите QuickHelp, то увидите, что они оба являются AnyObject

 

Прим: 

Ответить
Развернуть ветку
4 комментария
Раскрывать всегда