door Payal Gupta

het kopiëren van een object is altijd een essentieel onderdeel geweest van het codeerparadigma. Of het nu in Swift, Objective-C, JAVA of een andere taal is, we moeten altijd een object kopiëren voor gebruik in verschillende contexten.

in dit artikel zullen we in detail bespreken hoe verschillende gegevenstypen in Swift kunnen worden gekopieerd en hoe ze zich in verschillende omstandigheden gedragen.

waarde-en Referentietypen

alle gegevenstypen in Swift vallen globaal in twee categorieën, namelijk waardetypen en referentietypen.

  • waardetype-elk exemplaar bewaart een unieke kopie van zijn gegevens. Gegevenstypen die in deze categorie vallen, zijn onder meer — all the basic data types, struct, enum, array, tuples.
  • referentietype-instanties delen een enkele kopie van de gegevens, en het type wordt meestal gedefinieerd als een class.

het meest onderscheidende kenmerk van beide typen is hun kopieergedrag.

Wat is diepe en ondiepe kopie?

een instantie, of het nu een waardetype of een referentietype is, kan op een van de volgende manieren worden gekopieerd:

Deep copy — dupliceert alles

  • met een deep copy wordt elk object waarnaar door de bron wordt verwezen gekopieerd en wordt de kopie naar de bestemming verwezen. Dus twee volledig gescheiden objecten zullen worden gemaakt.
  • Collecties-een diepe kopie van een collectie is twee collecties waarbij alle elementen uit de oorspronkelijke collectie worden gedupliceerd.
  • minder vatbaar voor raceomstandigheden en presteert goed in een multithreaded omgeving — veranderingen in een object hebben geen effect op een ander object.
  • waardetypen worden diep gekopieerd.

in bovenstaande code,

  • Regel 1: arr1 – array (een waardetype) van tekenreeksen
  • regel 2: arr1 is toegewezen aan arr2. Dit zal een diepe kopie van arr1 maken en dan die kopie toewijzen aan arr2
  • regels 7 tot en met 11: Wijzigingen in arr2 komen niet terug in arr1 .

dit is wat deep copy is-volledig afzonderlijke instanties. Hetzelfde concept werkt met alle waarde types.

in sommige scenario ‘ s, dat wil zeggen wanneer een waardetype geneste referentietypen bevat, vertoont deep copy een ander soort gedrag. We zullen dat zien in de komende secties.

ondiepe kopie-duplicaten zo min mogelijk

  • met een ondiepe kopie wordt elk object waarnaar door de bron wordt verwezen ook aangeduid door de bestemming. Dus slechts één object zal worden gemaakt in het geheugen.
  • Collecties-een ondiepe kopie van een collectie is een kopie van de collectiestructuur, niet de elementen. Met een ondiepe kopie delen twee collecties nu de afzonderlijke elementen.
  • sneller – alleen de referentie wordt gekopieerd.
  • het kopiëren van referentietypen maakt een ondiepe kopie.

in bovenstaande code,

  • regels 1 tot en met 8: Address klasse — type
  • regel 10: a1 – een instantie van Address type
  • regel 11: a1 wordt toegewezen aan a2. Dit zal een ondiepe kopie van a1 maken en dan die kopie toewijzen aan a2, dat wil zeggen dat alleen de referentie wordt gekopieerd naar a2.
  • regels 16 tot en met 19: wijzigingen in a2 zullen zeker worden weerspiegeld in a1 .

in de bovenstaande afbeelding kunnen we zien dat zowel a1 als a2 naar hetzelfde geheugenadres verwijzen.

Referentietypen diep kopiëren

vanaf nu weten we dat wanneer we een referentietype proberen te kopiëren, alleen de verwijzing naar het object wordt gekopieerd. Er is geen nieuw object aangemaakt. Wat als we een volledig apart object willen maken?

we kunnen een diepe kopie van het referentietype maken met behulp van de copy() methode. Volgens de documentatie geeft

copy () – het object terug met copy(with:).

dit is een gemaksmethode voor klassen die het NSCopying – protocol gebruiken. Een uitzondering wordt gemaakt als er geen implementatie is voor copy(with:).

laten we de Address class die we hebben gemaakt in code fragment 2 herstructureren om te voldoen aan het NSCopying protocol.

In bovenstaande code,

  • regels 1 tot en met 14: Address klasse type is conform NSCopying en implementeert copy(with:) methode
  • regel 16: Address type
  • regel 17: a1 wordt toegewezen aan a2 met behulp van de methode copy(). Dit zal een diepe kopie van a1 maken en dan die kopie toewijzen aan a2, dat is een volledig nieuw object zal worden gemaakt.
  • regels 22 tot en met 25: Wijzigingen in a2 worden niet weerspiegeld in a1 .

zoals Uit bovenstaande afbeelding blijkt, wijzen zowel a1 als a2 naar verschillende geheugenlocaties.

laten we een ander voorbeeld bekijken. Deze keer zullen we zien hoe het werkt met geneste referentietypen — een referentietype dat een ander referentietype bevat.

In bovenstaande code,

  • regel 22: een diepe kopie van p1 wordt toegewezen aan p2 met behulp van de methode copy(). Dit houdt in dat elke wijziging in een van de twee geen gevolgen mag hebben voor de andere.
  • regels 27 tot en met 28: p2's name en city waarden worden gewijzigd. Deze waarden mogen niet worden weergegeven in p1.
  • regel 30: p1's name is zoals verwacht, maar zijn city? Het zou "Mumbai" moeten zijn, nietwaar? Maar dat zien we niet gebeuren. "Bangalore" was alleen voor p2 juist? Ja … precies.?

diep kopiëren…!? Dat was niet van jou verwacht. Je zei dat je alles zou kopiëren. En nu gedraag je je zo. Waarom oh waarom..?! Wat moet ik nu doen? ☠ ️

raak niet in paniek. Laten we eens kijken wat geheugenadressen hierin te zeggen heeft.

uit de bovenstaande illustratie kunnen we zien dat

  • p1 en p2 wijzen naar verschillende geheugenlocaties zoals verwacht.
  • maar hun address variabelen wijzen nog steeds naar dezelfde locatie. Dit betekent dat zelfs na het diep kopiëren alleen de referenties worden gekopieerd — dat wil zeggen, een oppervlakkige kopie natuurlijk.

opmerking:: elke keer dat we een referentietype kopiëren, wordt standaard een ondiepe kopie gemaakt totdat we expliciet specificeren dat het diep moet worden gekopieerd.

func copy(with zone: NSZone? = nil) -> Any{ let person = Person(self.name, self.address) return person}

in de bovenstaande methode die we eerder hebben geïmplementeerd voor de klasse Person, hebben we een nieuwe instantie gemaakt door het adres te kopiëren met self.address . Dit zal alleen de verwijzing naar het adres object kopiëren. Dit is de reden waarom zowel p1 als p2's address naar dezelfde locatie wijzen.

dus, het kopiëren van het object met behulp van de copy() methode zal geen echte diepe kopie van het object maken.

om een referentieobject volledig te dupliceren: het referentietype samen met alle geneste referentietypen moeten worden gekopieerd met de copy() methode.

let person = Person(self.name, self.address.copy() as? Address)

met behulp van de bovenstaande code in de func copy(with zone: NSZone? = nil) -> zal elke methode alles werkend krijgen. Dat zie je aan de onderstaande afbeelding.

True Deep Copy — Reference en Value types

we hebben al gezien hoe we een diepe kopie van de reference types kunnen maken. Natuurlijk kunnen we dat doen met alle geneste referentietypen.

maar hoe zit het met het geneste referentietype in een waardetype, dat een array van objecten is, of een variabele van het referentietype in een struct of misschien een tupel? Kunnen we dat ook oplossen met copy()? Nee, dat kunnen we niet, eigenlijk. De copy() methode vereist de implementatie van het NSCopying protocol dat alleen werkt voor NSObject subklassen. Waarde types ondersteunen geen overerving, dus we kunnen copy() niet gebruiken met hen.

in regel 2 wordt alleen de structuur van arr1 diep gekopieerd, maar de Address objecten erin zijn nog steeds ondiep gekopieerd. Dat kun je zien op de onderstaande geheugenkaart.

de elementen in zowel arr1 als arr2 wijzen beide naar dezelfde geheugenlocaties. Dit komt door dezelfde reden — referentietypes worden standaard ondiep gekopieerd.

serialiseren en vervolgens de-serialiseren van een object creëert altijd een gloednieuw object. Het is geldig voor zowel waarde types als de referentie types.

hier zijn enkele API ‘ s die we kunnen gebruiken om data te serialiseren en te de-serialiseren:

  1. NSCoding-een protocol waarmee een object kan worden gecodeerd en gedecodeerd voor archivering en distributie. Het zal alleen werken met class type objecten omdat het vereist dat erven van NSObject .
  2. Codable-maak uw gegevenstypen codable en decodable voor compatibiliteit met externe representaties zoals JSON. Het werkt voor zowel waardetypen – struct, array, tuple, basic data types als referentietypen – class .

laten we de Address Klasse Een beetje verder herstructureren om te voldoen aan het Codable protocol en alle NSCopying code verwijderen die we eerder in codefragment 3 hebben toegevoegd.

in de bovenstaande code maken regels 11-13 een echte diepe kopie van arr1. Hieronder is de illustratie die een duidelijk beeld van het geheugen locaties geeft.

Copy on Write

Copy on write is een optimalisatietechniek die helpt bij het verbeteren van de prestaties bij het kopiëren van waarde types.

laten we zeggen dat we een enkele String of Int of misschien een ander waardetype kopiëren — we zullen in dat geval geen cruciale prestatieproblemen tegenkomen. Maar wat als we een reeks van duizenden elementen kopiëren? Zal het nog steeds geen problemen met de prestaties veroorzaken? Wat als we het gewoon kopiëren en geen wijzigingen aanbrengen in die kopie? Is die extra herinnering die we gebruikten geen verspilling in die koffer?

hier komt het concept van Kopiëren in schrijven — bij het kopiëren wijst elke referentie naar hetzelfde geheugenadres. Alleen wanneer een van de referenties de onderliggende gegevens wijzigt, kopieert Swift de originele instantie en maakt de wijziging.

dat wil zeggen, of het nu een diepe kopie of een ondiepe kopie is, een nieuwe kopie zal niet worden gemaakt totdat we een wijziging in een van de objecten maken.

In bovenstaande code,

  • regel 2: een diepe kopie van arr1 is toegewezen aan arr2
  • regels 4 en 5: arr1 en arr2 wijzen nog steeds naar hetzelfde geheugenadres
  • regel 7: wijzigingen aangebracht in arr2
  • regels 9 en 10: arr1 en arr2 wijzen nu naar verschillende geheugenlocaties

nu weet u meer over diepe en ondiepe kopieën en hoe ze zich gedragen in verschillende scenario ‘ s met verschillende gegevenstypen. U kunt ze proberen met uw eigen set van voorbeelden en zien welke resultaten je krijgt.

verder lezen

vergeet niet mijn andere artikelen te lezen:

  1. alles over Codable in Swift 4
  2. alles wat u altijd al wilde weten over meldingen in iOS
  3. kleur het met verlopen — iOS
  4. Codering voor iOS 11: Hoe & slepen in Verzamelingen & tabellen
  5. alles wat u moet weten over Today Extensions (Widget) in iOS 10
  6. UICollectionViewCell selectie gemaakt rustig..!!

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.