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 aanarr2
. Dit zal een diepe kopie vanarr1
maken en dan die kopie toewijzen aanarr2
- regels 7 tot en met 11: Wijzigingen in
arr2
komen niet terug inarr1
.
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 vanAddress
type - regel 11:
a1
wordt toegewezen aana2
. Dit zal een ondiepe kopie vana1
maken en dan die kopie toewijzen aana2
, dat wil zeggen dat alleen de referentie wordt gekopieerd naara2
. - regels 16 tot en met 19: wijzigingen in
a2
zullen zeker worden weerspiegeld ina1
.

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 conformNSCopying
en implementeertcopy(with:)
methode - regel 16: Address type
- regel 17:
a1
wordt toegewezen aana2
met behulp van de methodecopy()
. Dit zal een diepe kopie vana1
maken en dan die kopie toewijzen aana2
, dat is een volledig nieuw object zal worden gemaakt. - regels 22 tot en met 25: Wijzigingen in
a2
worden niet weerspiegeld ina1
.

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 aanp2
met behulp van de methodecopy()
. 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
encity
waarden worden gewijzigd. Deze waarden mogen niet worden weergegeven inp1
. - regel 30:
p1's
name
is zoals verwacht, maar zijncity
? Het zou"Mumbai"
moeten zijn, nietwaar? Maar dat zien we niet gebeuren."Bangalore"
was alleen voorp2
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
enp2
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:
- 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 vanNSObject
. - 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 aanarr2
- regels 4 en 5:
arr1
enarr2
wijzen nog steeds naar hetzelfde geheugenadres - regel 7: wijzigingen aangebracht in
arr2
- regels 9 en 10:
arr1
enarr2
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:
- alles over Codable in Swift 4
- alles wat u altijd al wilde weten over meldingen in iOS
- kleur het met verlopen — iOS
- Codering voor iOS 11: Hoe & slepen in Verzamelingen & tabellen
- alles wat u moet weten over Today Extensions (Widget) in iOS 10
- UICollectionViewCell selectie gemaakt rustig..!!