Any и AnyObject в Swift: когда их стоит использовать?

Когда мы используем 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.

Читайте также:
Добавить комментарий

Ваш адрес email не будет опубликован.