it-swarm.com.de

Warum sollten Sie Struct über Klasse wählen?

Wenn Sie mit Swift spielen und aus einem Java-Hintergrund kommen, warum möchten Sie eine Struktur statt einer Klasse wählen? Es scheint, als wären sie dasselbe, wobei ein Struct weniger Funktionalität bietet. Warum also wählen?

423
bluedevil2k

Laut dem sehr populären WWDC 2015 Talk Protocol Oriented Programming in Swift ( video , transcript ) bietet Swift eine Reihe von Features, die Strukturen in vielen Situationen besser machen als Klassen.

Strukturen sind vorzuziehen, wenn sie relativ klein und kopierbar sind, da das Kopieren weitaus sicherer ist als mehrere Verweise auf dieselbe Instanz wie bei Klassen. Dies ist besonders wichtig, wenn eine Variable an viele Klassen übergeben wird und/oder in einer Multithread-Umgebung. Wenn Sie immer eine Kopie Ihrer Variablen an andere Orte senden können, müssen Sie sich nie darum kümmern, dass der andere Ort den Wert Ihrer Variablen unter sich ändert.

Mit Structs müssen Sie sich weniger Sorgen um Speicherverluste oder um mehrere Threads machen, um auf eine einzelne Instanz einer Variablen zuzugreifen oder diese zu ändern. (Für technisch Versierte ist die Ausnahme eine Ausnahme, wenn eine Struktur innerhalb einer Schließung erfasst wird, da dann tatsächlich ein Verweis auf die Instanz erfasst wird, sofern Sie sie nicht explizit als kopierbar markieren.

Klassen können auch aufgebläht werden, da eine Klasse nur von einer einzelnen Superklasse erben kann. Das ermutigt uns, riesige Superklassen zu schaffen, die viele verschiedene Fähigkeiten umfassen, die nur lose miteinander verbunden sind. Durch die Verwendung von Protokollen, insbesondere bei Protokollerweiterungen, bei denen Sie Implementierungen für Protokolle bereitstellen können, können Sie Klassen für dieses Verhalten nicht mehr benötigen.

Im Vortrag werden folgende Szenarien beschrieben, in denen Klassen bevorzugt werden:

  • Das Kopieren oder Vergleichen von Instanzen ist nicht sinnvoll (z. B. Fenster).
  • Die Lebensdauer der Instanz ist an externe Effekte gebunden (z. B. TemporaryFile).
  • Instanzen sind nur "Sinks" - schreibgeschützte Conduits in externen Status (z. B. CGContext)

Dies impliziert, dass Strukturen der Standard sein sollten und Klassen ein Fallback sein sollten.

Andererseits ist die Dokumentation The Swift Programming Language etwas widersprüchlich:

Strukturinstanzen werden immer nach Wert und Klasse .__ übergeben. Instanzen werden immer als Referenz übergeben. Dies bedeutet, dass sie .__ sind. geeignet für verschiedene Arten von Aufgaben. Da betrachten Sie die Daten Entscheiden Sie Konstrukte und Funktionen, die Sie für ein Projekt benötigen ob jedes Datenkonstrukt als Klasse oder als .__ definiert werden soll. Struktur.

Als allgemeine Richtlinie sollten Sie die Erstellung einer Struktur in Betracht ziehen, wenn eine oder mehrere dieser Bedingungen gelten:

  • Die Hauptaufgabe der Struktur besteht darin, einige relativ einfache Datenwerte zu kapseln.
  • Es kann davon ausgegangen werden, dass die gekapselten Werte kopiert werden und nicht referenziert werden, wenn Sie ein .__ zuweisen oder übergeben. Instanz dieser Struktur.
  • Alle Eigenschaften, die in der Struktur gespeichert werden, sind selbst Werttypen, von denen erwartet wird, dass sie kopiert und nicht referenziert werden.
  • Die Struktur muss Eigenschaften oder Verhalten nicht von einem anderen vorhandenen Typ erben.

Beispiele für gute Kandidaten für Strukturen sind:

  • Die Größe einer geometrischen Form, die möglicherweise eine Width-Eigenschaft und eine Height-Eigenschaft enthält, beide vom Typ Double.
  • Eine Möglichkeit, auf Bereiche innerhalb einer Serie zu verweisen, die möglicherweise eine Starteigenschaft und eine Längeneigenschaft kapselt, beide vom Typ Int.
  • Ein Punkt in einem 3D-Koordinatensystem, der möglicherweise die Eigenschaften x, y und z einschließt, jeweils vom Typ Double.

In allen anderen Fällen definieren Sie eine Klasse und erstellen Instanzen dieser Klasse verwaltet und als Referenz übergeben werden. In der Praxis bedeutet dies, dass Die meisten benutzerdefinierten Datenkonstrukte sollten Klassen und keine Strukturen sein.

Hier wird behauptet, wir sollten Klassen standardmäßig verwenden und Strukturen nur unter bestimmten Umständen verwenden. Letztendlich müssen Sie die Implikationen von Werttypen im Vergleich zu Referenztypen in der realen Welt verstehen und dann eine fundierte Entscheidung darüber treffen, wann Strukturen oder Klassen verwendet werden sollen. Denken Sie auch daran, dass sich diese Konzepte ständig weiterentwickeln und dass die Dokumentation zur Swift-Programmiersprache geschrieben wurde, bevor der Vortrag über protokollorientierte Programmierung stattfand.

499
drewag

Da Strukturinstanzen auf Stapel und Klasseninstanzen auf Heap zugewiesen werden, können Strukturen manchmal erheblich schneller sein.

Sie sollten es jedoch immer selbst messen und auf der Grundlage Ihres einzigartigen Anwendungsfalls entscheiden.

Betrachten Sie das folgende Beispiel, das zwei Strategien für den Umbruch des Datentyps Int mit struct und class veranschaulicht. Ich verwende 10 wiederholte Werte, um die reale Welt, in der Sie mehrere Felder haben, besser wiederzugeben.

class Int10Class {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

struct Int10Struct {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

func + (x: Int10Class, y: Int10Class) -> Int10Class {
    return IntClass(x.value + y.value)
}

func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
    return IntStruct(x.value + y.value)
}

Die Leistung wird mit gemessen

// Measure Int10Class
measure("class (10 fields)") {
    var x = Int10Class(0)
    for _ in 1...10000000 {
        x = x + Int10Class(1)
    }
}

// Measure Int10Struct
measure("struct (10 fields)") {
    var y = Int10Struct(0)
    for _ in 1...10000000 {
        y = y + Int10Struct(1)
    }
}

func measure(name: String, @noescape block: () -> ()) {
    let t0 = CACurrentMediaTime()

    block()

    let dt = CACurrentMediaTime() - t0
    print("\(name) -> \(dt)")
}

Code finden Sie unter https://github.com/knguyen2708/StructVsClassPerformance

UPDATE (27. März 2018):

Ab Swift 4.0, Xcode 9.2, mit Release Build auf iPhone 6S, iOS 11.2.6, ist der Swift Compiler -O -whole-module-optimization:

  • Die class-Version dauerte 2,06 Sekunden
  • struct-Version dauerte 4.17e-08 Sekunden (50.000.000-mal schneller)

(Ich durchschnittlich mehrere Läufe nicht mehr, da die Abweichungen sehr gering sind und unter 5% liegen.)

Note: Ohne vollständige Moduloptimierung ist der Unterschied weniger dramatisch. Ich würde mich freuen, wenn mir jemand zeigen kann, was die Flagge tatsächlich macht.


UPDATE (7. Mai 2016):

Ab Swift 2.2.1, Xcode 7.3, mit Release Build auf iPhone 6S, iOS 9.3.1, gemittelt über 5 Läufe, ist die Einstellung des Swift Compilers -O -whole-module-optimization:

  • Die class-Version benötigte 2.159942142s
  • struct-Version dauerte 5.83E-08s (37.000.000-mal schneller)

Note: Da jemand erwähnt hat, dass es in realen Szenarien wahrscheinlich mehr als 1 Feld in einer Struktur gibt, habe ich Tests für Strukturen/Klassen mit 10 Feldern anstelle von 1 hinzugefügt viel.


URSPRÜNGLICHE ERGEBNISSE (1. Juni 2014):

(Läuft auf struct/class mit 1 Feld, nicht 10)

Ab Swift 1.2, Xcode 6.3.2, läuft Release Build auf iPhone 5S, iOS 8.3, im Durchschnitt über 5 Läufe

  • Die class-Version benötigte 9.788332333s
  • struct-Version benötigte 0.010532942s (900-mal schneller)

ALTE ERGEBNISSE (aus unbekannter Zeit)

(Läuft auf struct/class mit 1 Feld, nicht 10)

Mit dem Release Build auf meinem MacBook Pro:

  • Die class-Version dauerte 1.10082 sek
  • Die struct-Version dauerte 0,02324 Sekunden (50-mal schneller)
148
Khanh Nguyen

Ähnlichkeiten zwischen Strukturen und Klassen.

Ich habe Gist dafür mit einfachen Beispielen erstellt https://github.com/objc-Swift/swift-classes-vs-structures

Und Unterschiede

1. Vererbung.

strukturen können in Swift nicht erben. Falls Sie es wollen

class Vehicle{
}

class Car : Vehicle{
}

Geh für eine Klasse.

2. Pass vorbei

Swift-Strukturen werden nach Wert und Klasseninstanzen nach Referenz übergeben.

Kontextuelle Unterschiede

Strukturkonstante und Variablen

Beispiel (bei der WWDC 2014 verwendet)

struct Point{

   var x = 0.0;
   var y = 0.0;

} 

Definiert eine Struktur namens Point.

var point = Point(x:0.0,y:2.0)

Nun, wenn ich versuche, das x zu ändern. Es ist ein gültiger Ausdruck.

point.x = 5

Aber wenn ich einen Punkt als konstant definiert habe.

let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.

In diesem Fall ist der gesamte Punkt unveränderlich konstant. 

Wenn ich stattdessen eine Klasse Point verwendet habe, ist dies ein gültiger Ausdruck. Weil in einer Klasse unveränderliche Konstante der Verweis auf die Klasse selbst nicht ihre Instanzvariablen ist (es sei denn, diese Variablen sind als Konstanten definiert)

59
MadNik

Hier sind einige andere Gründe zu prüfen:

  1. structs erhalten eine automatische Initialisierung, die Sie gar nicht im Code verwalten müssen.

    struct MorphProperty {
       var type : MorphPropertyValueType
       var key : String
       var value : AnyObject
    
       enum MorphPropertyValueType {
           case String, Int, Double
       }
     }
    
     var m = MorphProperty(type: .Int, key: "what", value: "blah")
    

Um dies in einer Klasse zu erhalten, müssten Sie den Initialisierer hinzufügen und keep den Initialisierer ... 

  1. Grundlegende Auflistungstypen wie Array sind Strukturen. Je mehr Sie sie in Ihrem eigenen Code verwenden, desto mehr gewöhnen Sie sich an das Übergeben von Werten im Gegensatz zu Verweisen. Zum Beispiel:

    func removeLast(var array:[String]) {
       array.removeLast()
       println(array) // [one, two]
    }
    
    var someArray = ["one", "two", "three"]
    removeLast(someArray)
    println(someArray) // [one, two, three]
    
  2. Scheinbar ist Unveränderlichkeit versus Mutabilität ein riesiges Thema, aber viele intelligente Leute meinen, dass Unveränderlichkeit - in diesem Fall Strukturen - vorzuziehen sind. Veränderliche gegen unveränderliche Objekte

28
Dan Rosenstark

Angenommen, wir kennen Struct ist ein Werttyp und Class ist ein Referenztyp.

Wenn Sie nicht wissen, was ein Werttyp und ein Referenztyp sind, dann sehen Sie/ Was ist der Unterschied zwischen Referenzübergabe und Wertübergabe?

Basierend auf Mikeashs Post :

... Zuerst einige extreme, offensichtliche Beispiele. Ganzzahlen sind offensichtlich kopierbar. Sie sollten Werttypen sein. Netzwerksteckdosen können nicht vernünftig kopiert werden. Sie sollten Referenztypen sein. Punkte wie in x, y Paare sind kopierbar. Sie sollten Werttypen sein. Ein Controller, der repräsentiert eine Platte, die nicht sinnvoll kopiert werden kann. Das sollte eine Referenz sein Art.

Einige Typen können kopiert werden, aber es ist möglicherweise nicht das, was Sie wollen die ganze Zeit passieren. Dies legt nahe, dass sie Verweise sein sollen Typen. Zum Beispiel kann eine Schaltfläche auf dem Bildschirm konzeptionell kopiert werden. Die Kopie ist nicht ganz identisch mit dem Original. Ein Klick auf die Kopie wird das Original nicht aktivieren. Die Kopie belegt nicht dieselbe Position auf dem Bildschirm. Wenn Sie den Button weitergeben oder in eine .__ einfügen. Neue Variable, die Sie wahrscheinlich auf die ursprüngliche Schaltfläche verweisen möchten, und Sie möchten nur eine Kopie erstellen, wenn dies ausdrücklich gewünscht wird. Das bedeutet, dass Ihr Schaltflächentyp ein Referenztyp sein sollte.

Ein ähnliches Beispiel sind View- und Window-Controller. Sie könnten sein Möglicherweise kopierbar, aber es ist fast nie das, was Sie tun möchten. Sie sollten Referenztypen sein.

Was ist mit den Modelltypen? Möglicherweise hat ein Benutzertyp einen Benutzer auf Ihrem System oder einem Crime-Typ, der eine von einer .__ ausgeführte Aktion darstellt. Nutzer. Diese sind ziemlich kopierbar, daher sollten sie wahrscheinlich den Wert .__ haben. Typen. Möglicherweise möchten Sie jedoch die Aktualisierungen eines in .__ vorgenommenen Verbrechens eines Benutzers durchführen. eine Stelle in Ihrem Programm, um für andere Teile des Programms sichtbar zu sein . Dies legt nahe, dass Ihre Benutzer von einer Art Benutzer verwaltet werden sollen Controller, der ein Referenztyp sein würde. z.B

struct User {}
class UserController {
    var users: [User]

    func add(user: User) { ... }
    func remove(userNamed: String) { ... }
    func ...
}

Sammlungen sind ein interessanter Fall. Dazu gehören Dinge wie Arrays und Wörterbücher sowie Zeichenfolgen. Sind sie kopierbar? Offensichtlich. Ist Etwas kopieren, das Sie leicht und häufig ausführen möchten? Das ist weniger klar.

Die meisten Sprachen sagen "Nein" und geben an, dass ihre Sammlungen auf .__ verweisen. Typen. Dies gilt für Objective-C und Java sowie Python und JavaScript und fast jede andere Sprache, die mir einfällt. (Eine wichtige Ausnahme Ist C++ mit STL-Auflistungstypen, aber C++ ist der rasende Irrer der Sprachwelt, die alles seltsam macht.)

Swift sagte "Ja", was bedeutet, dass Typen wie Array und Dictionary und String sind eher Strukturen als Klassen. Sie werden bei der Zuordnung kopiert, und als Parameter übergeben. Dies ist eine durchaus vernünftige Wahl. solange das Exemplar billig ist, versucht Swift sehr.. erreichen. ...

Verwenden Sie außerdem keine Klasse, wenn Sie jede Instanz einer Funktion überschreiben müssen, dh sie haben keine shared - Funktionalität.

Also anstatt mehrere Unterklassen einer Klasse zu haben. Verwenden Sie mehrere Strukturen, die einem Protokoll entsprechen.

18
Honey

Einige Vorteile:

  • automatisch fadensicher, da sie nicht gemeinsam genutzt werden kann
  • verbraucht weniger Speicher aufgrund von isa und refcount (und der Stack wird im Allgemeinen zugewiesen)
  • methoden werden immer statisch abgesetzt, daher können Inline eingefügt werden (obwohl @final dies für Klassen tun kann).
  • einfacher zu begründen (keine Notwendigkeit, "defensiv zu kopieren", wie es bei NSArray, NSString usw. üblich ist), aus demselben Grund wie Threadsicherheit
18
Catfish_Man

Die Struktur ist viel schneller als die Klasse. Wenn Sie Vererbung benötigen, müssen Sie auch Klasse verwenden. Der wichtigste Punkt ist, dass Class ein Referenztyp ist, während Structure ein Werttyp ist. zum Beispiel,

class Flight {
    var id:Int?
    var description:String?
    var destination:String?
    var airlines:String?
    init(){
        id = 100
        description = "first ever flight of Virgin Airlines"
        destination = "london"
        airlines = "Virgin Airlines"
    } 
}

struct Flight2 {
    var id:Int
    var description:String
    var destination:String
    var airlines:String  
}

jetzt können wir eine Instanz von beiden erstellen.

var flightA = Flight()

var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )

jetzt können wir diese Instanz an zwei Funktionen übergeben, die die ID, die Beschreibung, das Ziel usw. ändern.

func modifyFlight(flight:Flight) -> Void {
    flight.id = 200
    flight.description = "second flight of Virgin Airlines"
    flight.destination = "new york"
    flight.airlines = "Virgin Airlines"
}

ebenfalls,

func modifyFlight2(flight2: Flight2) -> Void {
    var passedFlight = flight2
    passedFlight.id = 200
    passedFlight.description = "second flight from virgin airlines" 
}

so,

modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)

wenn wir nun die ID und Beschreibung des FlightA ausdrucken, erhalten wir

id = 200
description = "second flight of Virgin Airlines"

Hier können wir sehen, dass die ID und die Beschreibung von FlightA geändert werden, da der an die Modifikationsmethode übergebene Parameter tatsächlich auf die Speicheradresse des FlightA-Objekts (Referenztyp) verweist.

wenn wir jetzt die ID und die Beschreibung der FLightB-Instanz drucken, erhalten wir 

id = 100
description = "first ever flight of Virgin Airlines"

Hier ist zu sehen, dass die FlightB-Instanz nicht geändert wird, da in der modifyFlight2-Methode die tatsächliche Instanz von Flight2 Durchgänge ist und nicht Verweise (Werttyp).

12
Manoj Karki

Beantwortung der Frage aus Sicht von Werttypen vs. Referenztypen aus diesem Apple-Blogbeitrag es erscheint sehr einfach:

Verwenden Sie einen Werttyp [z. struct, enum] wenn:

  • Der Vergleich von Instanzdaten mit == ist sinnvoll
  • Sie möchten, dass Kopien einen unabhängigen Status haben
  • Die Daten werden im Code über mehrere Threads hinweg verwendet

Verwenden Sie einen Referenztyp [z. Klasse] wenn:

  • Der Vergleich der Instanzidentität mit === ist sinnvoll
  • Sie möchten einen gemeinsamen, veränderbaren Status erstellen

Wie in diesem Artikel erwähnt, verhält sich eine Klasse ohne beschreibbare Eigenschaften mit einer struct identisch, wobei (ich möchte hinzufügen) eine Einschränkung gilt: structs eignen sich am besten für thread-sichere Modelle - eine zunehmend anstehende Anforderung in der modernen App-Architektur .

4
David James

Bei Klassen erhalten Sie Vererbung und werden als Referenz übergeben. Strukturen haben keine Vererbung und werden als Wert übergeben.

Es gibt großartige WWDC-Sitzungen zu Swift. Diese spezifische Frage wird in einer von ihnen ausführlich beantwortet. Stellen Sie sicher, dass Sie sich diese anschauen, da Sie dadurch schneller als mit dem Sprachführer oder dem iBook arbeiten können.

3
Joride

Ich würde nicht sagen, dass Strukturen weniger Funktionalität bieten.

Sicher, das Selbst ist unveränderlich, außer in einer veränderlichen Funktion, aber das war's auch schon.

Vererbung funktioniert gut, solange Sie an der guten alten Idee festhalten, dass jede Klasse entweder abstrakt oder endgültig sein sollte.

Implementieren Sie abstrakte Klassen als Protokolle und endgültige Klassen als Strukturen.

Das Schöne an Structs ist, dass Sie Ihre Felder veränderbar machen können, ohne einen gemeinsamen veränderbaren Status zu erstellen, da Copy-by-Write das erledigt :)

Deshalb sind die Eigenschaften/Felder im folgenden Beispiel alle veränderlich, was ich in Java oder C # oder Swift classes nicht tun würde.

Beispiel für eine Vererbungsstruktur mit etwas verschmutzter und unkomplizierter Verwendung am Ende der Funktion "example":

protocol EventVisitor
{
    func visit(event: TimeEvent)
    func visit(event: StatusEvent)
}

protocol Event
{
    var ts: Int64 { get set }

    func accept(visitor: EventVisitor)
}

struct TimeEvent : Event
{
    var ts: Int64
    var time: Int64

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }
}

protocol StatusEventVisitor
{
    func visit(event: StatusLostStatusEvent)
    func visit(event: StatusChangedStatusEvent)
}

protocol StatusEvent : Event
{
    var deviceId: Int64 { get set }

    func accept(visitor: StatusEventVisitor)
}

struct StatusLostStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var reason: String

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

struct StatusChangedStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var newStatus: UInt32
    var oldStatus: UInt32

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

func readEvent(fd: Int) -> Event
{
    return TimeEvent(ts: 123, time: 56789)
}

func example()
{
    class Visitor : EventVisitor
    {
        var status: UInt32 = 3;

        func visit(event: TimeEvent)
        {
            print("A time event: \(event)")
        }

        func visit(event: StatusEvent)
        {
            print("A status event: \(event)")

            if let change = event as? StatusChangedStatusEvent
            {
                status = change.newStatus
            }
        }
    }

    let visitor = Visitor()

    readEvent(1).accept(visitor)

    print("status: \(visitor.status)")
}
2
yeoman

In Swift wurde ein neues Programmiermuster eingeführt, das als Protocol Oriented Programming (Protokollorientierte Programmierung) bekannt ist.

Kreationsmuster:

In Swift ist Struct ein Werttyp , der automatisch geklont wird. Daher erhalten wir das erforderliche Verhalten, um das Prototypmuster kostenlos zu implementieren. 

Während Klassen sind der Referenztyp, der während der Zuweisung nicht automatisch geklont wird. Um das Prototypmuster zu implementieren, müssen Klassen das NSCopying-Protokoll übernehmen.


Flache Kopie dupliziert nur die Referenz, die auf diese Objekte verweist, während tiefe Kopie die Objektreferenz.


Die Implementierung von deep copy für jeden Referenztyp ist zu einer langwierigen Aufgabe geworden. Wenn Klassen weitere Referenztypen enthalten, müssen wir ein Prototypmuster für jede der Referenzeigenschaften implementieren. Und dann müssen wir tatsächlich das gesamte Objektdiagramm kopieren, indem Sie das NSCopying-Protokoll implementieren.

class Contact{
  var firstName:String
  var lastName:String
  var workAddress:Address // Reference type
}

class Address{
   var street:String
   ...
} 

Durch die Verwendung von structs und enums haben wir unseren Code vereinfacht, da wir die Kopierlogik nicht implementieren müssen.

2
Balasubramanian

Structs sind value type und Classes sind reference type

  • Werttypen sind schneller als Referenztypen
  • Werttypinstanzen sind in einer Umgebung mit mehreren Threads sicher, da Mehrere Threads die Instanz mutieren können, ohne dass sie sich über die Race-Bedingungen oder Deadlocks Sorgen machen müssen
  • Der Werttyp hat keine anderen Referenzen als den Referenztyp. daher gibt es keine Speicherlecks.

Verwenden Sie einen value-Typ, wenn:

  • Wenn Sie möchten, dass Kopien einen unabhängigen Status haben, werden die Daten in Code über mehrere Threads hinweg verwendet

Verwenden Sie einen reference-Typ, wenn:

  • Sie möchten einen gemeinsamen, veränderbaren Status erstellen.

Weitere Informationen finden Sie auch in der Apple-Dokumentation

https://docs.Swift.org/Swift-book/LanguageGuide/ClassesAndStructures.html


Zusätzliche Information

Swift-Werttypen werden im Stack gespeichert. In einem Prozess verfügt jeder Thread über einen eigenen Stapelspeicherbereich, sodass kein anderer Thread direkt auf Ihren Werttyp zugreifen kann. Daher keine Race-Bedingungen, Sperren, Deadlocks oder verwandte Thread-Synchronisationskomplexität.

Werttypen benötigen keine dynamische Speicherzuweisung oder Referenzzählung, was beide kostspielige Operationen sind. Gleichzeitig werden Methoden zu Werttypen statisch versendet. Dies schafft einen großen Vorteil gegenüber den Werttypen in Bezug auf die Leistung.

Zur Erinnerung hier eine Liste von Swift 

Werttypen:

  • Struktur
  • Enum
  • Tupel
  • Grundelemente (Int, Double, Bool usw.)
  • Sammlungen (Array, String, Wörterbuch, Set)

Referenztypen:

  • Klasse
  • Alles, was von NSObject kommt
  • Funktion
  • Schließung
1
casillas

Viele Cocoa-APIs erfordern NSObject-Unterklassen, sodass Sie Klassen verwenden müssen. Ansonsten können Sie die folgenden Fälle aus dem Swift-Blog von Apple verwenden, um zu entscheiden, ob Sie einen Strukturtyp/Enum-Werttyp oder einen Klassenreferenztyp verwenden möchten.

https://developer.Apple.com/Swift/blog/?id=10

1
akshay

Da struct Werttypen ist, können Sie sehr einfach den Speicher erstellen, der in den Stapel abgelegt wird. Struktur ist leicht zugänglich, und nach dem Umfang der Arbeit kann er leicht aus dem Stapelspeicher durch Popup von der Oberseite des Stapels aufgehoben werden Die andere Klasse ist ein Referenztyp, der in einem Heap gespeichert wird, und Änderungen, die in einem Klassenobjekt vorgenommen werden, wirken sich auf andere Objekte aus, da sie eng miteinander verbunden sind und ein Referenztyp ist. Alle Mitglieder einer Struktur sind öffentlich, während alle Mitglieder einer Klasse privat sind.

Die Nachteile von struct sind, dass es nicht vererbbar ist.

0
Tapash Mollick

Ein Punkt, der bei diesen Antworten keine Beachtung findet, ist, dass eine Variable, die eine Klasse gegen eine Struktur hält, eine let sein kann, während sie weiterhin Änderungen an den Eigenschaften des Objekts zulässt, während dies bei einer Struktur nicht möglich ist.

Dies ist nützlich, wenn Sie nicht möchten, dass die Variable auf ein anderes Objekt zeigt, das Objekt jedoch noch geändert werden muss, d. H., Wenn viele Instanzvariablen vorhanden sind, die Sie nacheinander aktualisieren möchten. Wenn es sich um eine Struktur handelt, müssen Sie zulassen, dass die Variable mithilfe von var vollständig auf ein anderes Objekt zurückgesetzt wird, da ein konstanter Werttyp in Swift eine Null-Mutation zulässt, während Referenztypen (Klassen) sich nicht auf diese Weise verhalten .

0
johnbakers