Any і AnyObject в Swift. У чому їх відмінність?

  • 12 января, 15:17
  • 3772
  • 0

Багато програмістів при написанні коду використовують тип Any, наприклад при обробці JSON даних. Але також є і другий тип - AnyObject. Яка ж різниця між цими двома типами?

Згідно з документацією Apple:

  1. Any - може представляти екземпляр будь-якого типу
  2. AnyObject - може представляти екземпляр будь-якого класу

Якщо сказати трохи простіше, то:

  1. Any використовується для всіх типів
  2. 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

Can not convert value of type «Int» to expected element type «AnyObject»

Can not convert value of type «Int» to expected element type «AnyObject»

Can not 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.

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


0 комментариев
Сортировка:
Добавить комментарий