Mis tahes versiooni AnyObject versioonis Swift 3.0

Kui ma kohtusin neid kahte tüüpi varjunime JSON-i andmeid esimest korda parsides, polnud mul aimugi, kuidas neid õigesti eristada või rakendada. Mis need siis on? Any ja AnyObject on Swiftis kaks eritüüpi, mida kasutatakse mittespetsiifiliste tüüpidega töötamiseks.

Apple'i Swifti dokumentatsiooni kohaselt

  • Igaüks võib esindada mis tahes tüüpi eksemplari, sealhulgas funktsioonitüübid ja valikulised tüübid.
  • AnyObject võib esindada mis tahes klassi tüüpi eksemplari.

Olgu, piisavalt lihtne - igat tüüpi kasutatakse igat tüüpi, AnyObjectit klassitüüpide jaoks, eks?

Mõistmaks, kuidas nad koodiga tegelikult käituvad, otsustasin mängida nendega Playgroundis.

Mis tahes näide

Kõik lubasid mul töötada erinevate tüüpide seguga, sealhulgas funktsiooni- ja klassivälised tüübid, näiteks Int, String ja Bool. Dokumentatsiooni kohaselt on selle massiivi elemendid väärtustüübid Struktuurid, nii et teoreetiliselt ei tohiks AnyObject sellistel juhtudel töötada.

Selle kontrollimiseks proovisin AnyObjecti abil lisada Swiftis väärtustüüpe Stringid ja Ints.

AnyObjectArray tõrge struudutüüpide lisamisel

Ootuspäraselt viskas kompilaator mulle vea, öeldes, et elemendid ei vasta massiivi tüübile AnyObject. Gotcha!

Siis juhtus see kummaline asi, kui üritasin järgida kompilaatori soovitusi:

AnyObjecti valatud elemendid

Mis just juhtus?! Kuidas sain AnyObjectit kasutada sisendites ja stringides, lastes selgesõnaliselt iga elemendi AnyObjectisse?

Seejärel printisin anyObjectArray konsooli.

AnyObjectArray printimine

Element Hi nägi minu jaoks ilmselgelt välja nagu string, kuid sellel polnud tsitaate nagu tavalises Swift-väärtuses!

Järgmisena printisin iga elemendi sisseehitatud silmuse abil, et kontrollida selle tegelikku tüüpi, mitte AnyObjecti valatud tüüpi.

Esiteks kasutasin operaatorit, et näha, kas elemendid on Swift Struct tüüpi või mitte.

Elementide tüüpide kontrollimine programmis anyObjectArray 1

See on tüüpi String! Kuidas saaks seda AnyObjectile laita? Jällegi on Swifti keelpillid struudid, mitte klassitüübid. Seega ei tohiks ma teoreetiliselt neid AnyObjectiks nimetada.

Mida?

Olin täiesti segaduses ja otsustasin sellega veel mõned katsed teha. Seekord kasutasin iga elemendi tüübi kontrollimiseks NSNumber ja NSString, mis on Objective-C tüübid.

Elementide tüüpide kontrollimine programmis anyObjectArray 2

Oota, Tere on ka NSString ja numbrilised elemendid on NSNumber! Ja… nad on Object-C viitetüübid! Kas see oli põhjus, miks Hiil polnud konsoolis selle kohta tsitaate? Kirjutasin veel mõne koodi, nagu allpool näha, kas minu eeldus oli õige.

NSString-massiivi ja stringimassiivi printimineTere, kui konsoolis pole NSStringina ühtegi tsitaati sisse lülitatud

Kinnitatud! Elemendid, mis massiivi AnyObject-i valatakse, on nüüd Objective-C klassi tüübid: NSString ja NSNumber.

Nii et ... mis tegelikult kapoti all toimub? Jätkasin selle teemaga tutvumist ja leidsin kõige usaldusväärsema vastuse dokumendist Swifti kasutamine kakao ja Objective-C abil (Swift 3.0.1).

Objective-C koostalitlusvõime osana pakub Swift mugavaid ja tõhusaid viise kakaoraamistikega töötamiseks. Swift teisendab automaatselt mõned Objective-C tüübid Swift-tüüpideks ja mõned Swift-tüübid Objective-C-tüüpideks. Tüüpe, mida saab teisendada Objective-C ja Swifti vahel, nimetatakse sillatüüpideks.
Igal pool, kus saate kasutada sillatud Objective-C viitetüüpi, võite selle asemel kasutada väärtuse tüüpi Swift. See võimaldab teil kasutada viitetüübi rakenduses saadaolevaid funktsioone viisil, mis on Swifti koodis loomulik. Sel põhjusel ei peaks te peaaegu kunagi kasutama sillatud viitetüüpi otse oma koodis. Tegelikult, kui Swift-kood impordib Objective-C API-sid, asendab importija Objective-C viitetüübid vastavate väärtustüüpidega. Samuti, kui Objective-C-kood impordib Swifti API-sid, asendab importija ka Swifti väärtuse tüübid vastavate Objective-C viitetüüpidega. ”

Teisisõnu teeb kompilaator kõik endast oleneva, et olla paindlik selliste tüüpide käsitlemisel automaatse muundamise ja sildade kaudu, vältides samal ajal meie rakenduse kergemat krahhi. Geniaalne!

Millal me siis AnyObjekti tegelikult kasutame? Nagu Apple'i dokumentatsioonis öeldud, saab AnyObjectit kasutada objektidega, mis pärinevad klassist, kuid millel pole ühist juurklassi.

Kuid kas seda on meie koodis tingimata vaja kasutada?

Minu vastus sellele küsimusele on: Ei.

Apple ütleb:

Swift 3-s tähistab id-tüüp Objective-C-s nüüd suvalist tüüpi Swiftis, mis kirjeldab mis tahes tüüpi väärtust, olgu see klass, enum, struct või mõni muu Swift-tüüp. See muudatus muudab Objective-C API-d Swiftis paindlikumaks, kuna Swifti määratletud väärtustüüpe saab edastada Objective-C API-dele ja ekstraheerida Swift-tüüpidena, välistades vajaduse käsitsi kasti tüüpide järele.
Need eelised laienevad ka kogudele: Objective-C kollektsiooni tüübid NSArray, NSD Dictionary ja NSSet, mis varem aktsepteerisid vaid AnyObjekti elemente, saavad nüüd hoida mis tahes tüüpi elemente. Räsitud konteinerite (nt sõnaraamat ja komplekt) jaoks on olemas uut tüüpi AnyHashable, mis suudab hoida igat tüüpi väärtust, mis vastab protokollile Swift Hashable.

Näib, et igaüks üksi töötab nende kahe keele ühendamisel Swift 3-s suurepäraselt suurepäraselt, ilma et oleks vaja AnyObjekti kasutada!

Mis oli nende muudatuste peamine põhjus?

Nende enda sõnul selgitab Apple:

Swift 3 liidesed Objective-C API-dega võimsamal viisil kui eelmised versioonid. Näiteks Swift 2 kaardistas id-objektiivi Objective-C tüübis AnyObject-tüübiga Swiftis, mis tavaliselt mahutab ainult klassitüüpide väärtusi. Swift 2 pakkus mugavuse huvides ka kaudseid teisendusi AnyObjectisse mõne sillatud väärtuse tüübi jaoks, nagu näiteks string, massiiv, sõnaraamat, komplekt ja mõned numbrid, et natiivseid Swifti tüüpe saaks hõlpsasti kasutada kakao API-dega, mis eeldasid NSStringut, NSArray, või muud Foundationi konteineriklassid. Need teisendused olid ülejäänud keelega vastuolus, muutes keeruliseks mõista, mida täpselt võiks AnyObjectina kasutada, mille tulemuseks olid vead.

Võib siiski rõhutada, et meie, iOS-i arendajad, peame koodides tüüpide kasutamise osas olema alati võimalikult konkreetsed.

Tõepoolest, Apple soovitab:

Kasutage suvandit Any ja AnyObject ainult siis, kui vajate selgesõnaliselt nende pakutavat käitumist ja võimalusi. Alati on parem täpsustada, millised tüübid teie koodis töötavad.

Mõelge sellele stsenaariumile: töötame Swiftis numbriga 12.5. Sel juhul ütleme konkreetselt, et see on topelt- või ujukitüüp, mitte ei kuuluta seda suvaliseks. Nii pääseme mugavalt juurde erinevatele omadustele või meetoditele, mis on selle konkreetse tüübi jaoks saadaval. Selles kontekstis kasutaksime klassitüüpide jaoks AnyObjectit, kuna need on pisut täpsemad kui Any. Kuid jällegi on AnyObjecti kasutamine lihtsalt võimalus.

Loodan, et see ajaveebi postitus aitas paljudel teist suurepäraseid arendajaid Any ja AnyObjekti täpsustamiseks. Kasutage suvalist suvandit Swift 3, töötades koos Objective-C toetatud API-dega.

Täname lugemise ja õnneliku kodeerimise eest!