Djúpt eintak vs grunnt eintak - og hvernig þú getur notað þau í Swift

Að afrita hlut hefur alltaf verið ómissandi þáttur í kóða forritunarinnar. Hvort sem það er á Swift, Objectivity-C, JAVA eða öðru tungumáli, þá verðum við alltaf að afrita hlut til notkunar í mismunandi samhengi.

Í þessari grein munum við ræða ítarlega hvernig á að afrita mismunandi gagnategundir í Swift og hvernig þær hegða sér við mismunandi kringumstæður.

Gildi og tilvísunargerðir

Allar gagnategundirnar í Swift falla í stórum dráttum í tvo flokka, nefnilega gildistegundir og viðmiðunartegundir.

  • Gildisgerð - hvert tilvik geymir einstakt afrit af gögnum sínum. Gagnategundir sem falla í þennan flokk fela í sér - allar grunngagnategundir, struct, enum, array, tuples.
  • Tilvísunargerð - tilvik deila einu afriti af gögnum og tegundin er venjulega skilgreind sem flokkur.

Það aðgreinandi sem einkennir báðar tegundirnar liggur í afritunarhegðun þeirra.

Hvað er Deep and Shallow copy?

Hægt er að afrita dæmi, hvort sem um er að ræða gildi eða tilvísunargerð á einn af eftirfarandi leiðum:

Djúpt eintak - afrit allt

  • Með djúpu afriti er afritað af hverjum hlut sem heimildarmaðurinn vísar til og afritinu vísað á afritið. Svo tveir alveg aðskildir hlutir verða búnir til.
  • Söfn - Djúpt eintak af safni eru tvö söfn þar sem allir þættirnir í upprunalegu safninu eru tvíteknir.
  • Minni tilhneigingu til hlaupsins og stendur sig vel í fjölþróuðu umhverfi - breytingar á einum hlut hafa engin áhrif á annan hlut.
  • Gildistegundir eru afritaðar djúpt.

Í ofangreindum kóða

  • Lína 1: arr1 - fylki (gildi gerð) af strengjum
  • Lína 2: arr1 er úthlutað til arr2. Þetta mun búa til djúpt eintak af arr1 og úthluta því afriti á arr2
  • Línur 7 til 11: allar breytingar sem gerðar eru í arr2 endurspegla ekki í arr1.

Þetta er það sem djúpt eintak er - alveg aðskildar tilvik. Sama hugtak virkar með allar gildistegundir.

Í sumum tilfellum, það er þegar gildi gerð inniheldur nestaðar viðmiðunartegundir, sýnir djúpt afrit annars konar hegðun. Við munum sjá það í komandi hlutum.

Grunt afrit - Afrit eins lítið og mögulegt er

  • Með grunnu afriti er einnig bent á ákvörðunarstað hvers hlutar sem heimildarmaðurinn vísar til. Svo aðeins einn hlutur verður til í minningunni.
  • Söfn - Grunt afrit af safni er afrit af söfnuninni en ekki þættirnir. Með grunnu afriti deila tvö söfn nú einstökum þáttum.
  • Hraðari - aðeins tilvísunin er afrituð.
  • Með því að afrita tilvísunartegundir myndast grunnt eintak.

Í ofangreindum kóða

  • Línur 1 til 8: Tegund tegund heimilisfangs
  • Lína 10: a1 - dæmi um tegund heimilisfangs
  • Lína 11: a1 er úthlutað til a2. Þetta mun búa til grunnt eintak af a1 og úthluta því afritinu til a2, það er aðeins tilvísunin er afrituð í a2.
  • Línur 16 til 19: allar breytingar sem gerðar eru í a2 munu vissulega endurspeglast í a1.

Á myndinni hér að ofan getum við séð að bæði a1 og a2 benda á sama minnisfang.

Afritun tilvísunargerða djúpt

Eins og nú vitum við að alltaf þegar við reynum að afrita tilvísunargerð er aðeins afritun til hlutarins afrituð. Enginn nýr hlutur er búinn til. Hvað ef við viljum búa til alveg sérstakan hlut?

Við getum búið til djúpt eintak af tilvísunargerðinni með afritunaraðferðinni (). Samkvæmt skjölunum,

copy () - Skilar hlutnum sem er skilað með afriti (með :).

Þetta er þægindaaðferð fyrir flokka sem nota NSCopying samskiptareglur. Undantekning er gerð ef engin framkvæmd er til afritunar (með :).

Við skulum endurskipuleggja Address bekkinn sem við bjuggum til í Code Snippet 2 til að vera í samræmi við NSCopying samskiptareglur.

Í ofangreindum kóða

  • Línur 1 til 14: Tegund tegund heimilisföng er í samræmi við NSCopying og útfærir afrit (með :) aðferð
  • Lína 16: a1 - dæmi um tegund heimilisfangs
  • Lína 17: a1 er úthlutað til a2 með afritunaraðferð () aðferð. Þetta mun búa til djúpt eintak af a1 og úthluta því afritinu til a2, það er alveg nýr hlutur verður til.
  • Línur 22 til 25: allar breytingar sem gerðar eru í a2 endurspeglast ekki í a1.

Eins og sést á myndinni hér að ofan benda bæði a1 og a2 á mismunandi minnisstaðsetningar.

Við skulum skoða annað dæmi. Að þessu sinni sjáum við hvernig það virkar með nestaðar tilvísanagerðir - tilvísunargerð sem inniheldur aðra tilvísunargerð.

Í ofangreindum kóða

  • Lína 22: djúpt eintak af p1 er úthlutað til p2 með afritunaraðferðinni (). Þetta felur í sér að allar breytingar á annarri þeirra mega ekki hafa nein áhrif á hina.
  • Línur 27 til 28: Nafni p2 og borgargildum er breytt. Þetta má ekki endurspegla í p1.
  • Lína 30: nafn p1 er eins og búist var við, en borgin hennar? Það ætti að vera „Mumbai“ ætti það ekki? En við getum ekki séð að það gerist. “Bangalore” var aðeins fyrir p2 ekki satt? Jamm… nákvæmlega.

Djúpt eintak…! Það var ekki búist við því af þér. Þú sagðir að þú munt afrita allt. Og núna hegðar þér þér svona. Af hverju ó hvers vegna ..?! Hvað geri ég núna?

Ekki örvænta. Við skulum líta á hvað minnið tekur til sín í þessu.

Af myndinni hér að ofan getum við séð það

  • p1 og p2 benda á mismunandi minni staði eins og búist var við.
  • En heimilisfang breytur þeirra eru enn að benda á sama stað. Þetta þýðir að jafnvel eftir að hafa afritað þær djúpt eru aðeins tilvísanirnar afritaðar - það er að segja grunnt afrit auðvitað.

Vinsamlegast athugið: í hvert skipti sem við afritum tilvísunargerð er grunnt afrit búið til sjálfgefið þar til við tilgreinum beinlínis að það eigi að afrita það djúpt.

func eintak (með svæði: NSZone? = núll) -> Allir
{
    láta mann = manneskja (sjálf.nafn, sjálf.aðgang)
    aftur einstakling
}

Í ofangreindri aðferð sem við innleiddum fyrr fyrir Persónu bekkinn höfum við búið til nýtt dæmi með því að afrita heimilisfangið með self.address. Þetta mun aðeins afrita tilvísunina í heimilisfangið. Þetta er ástæðan fyrir því að heimilisfang p1 og p2 bendir á sama stað.

Þannig að afritun hlutarins með afritunaraðferðinni () notar ekki raunverulegt djúpt eintak af hlutnum.

Til að afrita tilvísunarhlut fullkomlega: afritunargerðina ásamt öllum nestuðum viðmiðunargerðum verður að afrita með afritunaraðferðinni ().

láta mann = manneskja (sjálf.nafn, sjálf.aðganga.rit () sem? heimilisfang)

Notkun ofangreindra kóða í func eintakinu (með svæði: NSZone? = Nil) -> Allir aðferðir fá allt til að virka. Þú getur séð það af myndinni hér að neðan.

True Deep Copy - Tilvísunar- og gildistegundir

Við höfum þegar séð hvernig við getum búið til djúpt eintak af tilvísunargerðum. Auðvitað getum við gert það með öllum nestuðum viðmiðunartegundum.

En hvað um nestaða viðmiðunartegundina í gildi gerð, það er fylki af hlutum, eða tilvísunargerð breytu í uppbyggingu eða kannski tuple? Getum við leyst það með því að nota afrit () líka? Nei við getum það ekki. Aðferðin fyrir afritun () krefst þess að innleiða NSCopying samskiptareglur sem aðeins virka fyrir undirflokka NSObject. Gildistegundir styðja ekki arf, svo við getum ekki notað afrit () með þeim.

Í línu 2 er aðeins uppbygging arr1 djúpt afrituð, en heimilisfang hlutanna í henni eru enn grunnt afritaðir. Þú getur séð það af minniskortinu hér að neðan.

Þættirnir bæði arr1 og arr2 benda báðir á sömu minnisstöðvar. Þetta er af sömu ástæðu - viðmiðunartegundir eru grunnar afritaðar sjálfgefið.

Að raðgreina og síðan afgreina hlutinn skapar alltaf glænýjan hlut. Það gildir bæði fyrir gildi gerða sem og viðmiðunartegundir.

Hér eru nokkur API sem við getum notað til að raðgreina og afþreyta gagna:

  1. NSCoding - Siðareglur sem gera kleift að umrita og afkóða hlut fyrir geymslu og dreifingu. Það mun aðeins vinna með hlutum af gerðinni þar sem það krefst erfðar frá NSObject.
  2. Kóðanleg - Gerðu gagnategundirnar þínar umbreytanlegar og afkóðanlegar fyrir samhæfi við utanaðkomandi framsetningar eins og JSON. Það mun virka fyrir báðar gildistegundir - burðarvirki, fylki, kippur, grunngagnategundir sem viðmiðunartegundir - flokkur.

Við skulum endurskipuleggja Address bekkinn aðeins lengra til að samræmast Codable-samskiptareglunum og fjarlægja allan NSCopying kóða sem við bættum við fyrr í Code Snippet 3.

Í ofangreindum kóða mun línur 11–13 búa til raunverulegt djúpt eintak af arr1. Hér að neðan er myndin sem gefur skýra mynd af minnisstöðum.

Afrita á Writ

Afritun á ritun er hagræðingartækni sem hjálpar til við að auka afköst þegar afritun verðmætategunda er gerð.

Við skulum segja að við afritum einn streng eða millifærslu eða kannski einhverja aðra gildi - við stöndum ekki frammi fyrir mikilvægum árangursatriðum í því tilfelli. En hvað um það þegar við afritum fjölda þúsunda þátta? Mun það samt ekki skapa nein árangursmál? Hvað ef við afritum það bara og gerum engar breytingar á því eintaki? Er það ekki aukaminnið sem við notuðum bara sóun í því tilfelli?

Hér kemur hugtakið Afrita í skrifa - við afritun bendir hver tilvísun á sama minnisfang. Það er aðeins þegar ein tilvísunarinnar breytir undirliggjandi gögnum sem Swift afritar upphaflega dæmið og gerir breytinguna.

Það er, hvort sem það er djúpt eintak eða grunnt eintak, nýtt eintak verður ekki búið til fyrr en við gerum breytingu á einum af hlutunum.

Í ofangreindum kóða

  • Lína 2: djúpt eintak af arr1 er úthlutað til arr2
  • Línur 4 og 5: arr1 og arr2 benda enn á sama minnis heimilisfang
  • Lína 7: breytingar gerðar á arr2
  • Línur 9 og 10: arr1 og arr2 sem benda nú á mismunandi minni staði

Nú þú veist meira um djúp og grunn eintök og hvernig þau hegða sér í mismunandi sviðum með mismunandi gagnategundum. Þú getur prófað þau með eigin safni af dæmum og séð hvaða árangur þú færð.

Nánari lestur

Ekki gleyma að lesa aðrar greinar mínar:

  1. Allt um Codable í Swift 4
  2. Allt sem þú hefur alltaf viljað vita um tilkynningar í iOS
  3. Litar það með GRADIENTS - iOS
  4. Forritun fyrir iOS 11: Hvernig á að draga og sleppa í söfn og töflur
  5. Allt sem þú þarft að vita um í dag eftirnafn (búnaður) í iOS 10
  6. UICollectionViewCell valið var auðvelt .. !!

Feel frjáls til að skilja eftir athugasemdir ef þú hefur einhverjar spurningar.