2016-07-25 7 views
6

Mein Anwendungsfall ist auf dem folgende Modell zugrunde:Ist es möglich, eine bidirektionale Beziehung zwischen zwei Strukturen mit nur konstanten Eigenschaften zu implementieren?

struct Person { 
    let name: String 
    let houses: [House] 
} 

struct House { 
    let owner: Person 
} 

Jetzt, im Idealfall würde Ich mag eine bidirektionale Beziehung aufrecht zu erhalten, die jedes Haus hat genau einen Eigentümer erfordert, wo ein Eigentümer auch alle seine Häuser wissen sollte.

Mit den oben genannten Datenstrukturen ist es möglich, Instanzen von House und Person so zu erstellen, dass es eine Beziehung zwischen den beiden gibt und die Objekte im Wesentlichen aufeinander zeigen?

Ich denke, die Formulierung dieser ist schon etwas irreführend, weil sie aufgrund der Wertesemantik von struct s nicht wirklich irgendwo zeigen, sondern nur Kopien von Werten halten. Es scheint, als ob es offensichtlich sein sollte, dass es nicht möglich ist, diese beiden Objekte mit einer bidirektionalen Beziehung zu erstellen, aber ich wollte trotzdem sicher sein und diese Fragen hier stellen!

struct Person { 
    let name: String 
    var houses: [House] 

    init(name: String, houses: [House]) { 
    self.name = name 
    self.houses = houses 
    self.houses = houses.map { (house: House) in 
     var newHouse = house 
     newHouse.owner = self 
     return newHouse 
    } 
    } 
} 


struct House { 
    var owner: Person 

    init(owner: Person) { 
    self.owner = owner 
    var newHouses = self.owner.houses 
    newHouses.append(self) 
    self.owner = Person(name: owner.name, houses: newHouses) 
    } 
} 

Was aber, wenn ich:

Eine offensichtliche Lösung wäre auch houses und owner Variablen statt let mit var zu machen, wenn sie zu deklarieren, dann könnte die Beziehung in der initializer jedes struct gehalten werden wollen houses und owner konstant halten? Wie ich schon sagte, es ist offensichtlich, dass es nicht möglich ist, aber ich frage mich, ob es einen ausgefallenen (vielleicht funktionalen) Weg gibt, dies zu erreichen? Ich dachte über lenses, die als Getter und Setter verwendet werden können, wenn es um unveränderliche Modelle geht.

+1

Ich würde dringend davon abraten, irgendwelche * "wirklich selbstreferentiellen" * In-Memory-Datenstrukturen zu erstellen ... in Swift oder in einer anderen Programmiersprache. Warum? Weil es dem Speichermanager sehr schwer fällt: Es kann aufgrund von Zirkelverweisen zu "Speicherlecks" kommen. Außerdem: Mach diese "nur Strukturen" nicht. Lass sie die "Objekte" sein, die sie natürlich sind. –

Antwort

4

Was Sie beschreiben, klingt mehr wie ein ORM als ein Sprachfeature und klingt auch nicht angemessen, um mit Werttypen wie Strukturen umzugehen. Wie erwarten Sie, dass die Sprache weiß, dass owner die inverse Beziehungseigenschaft houses ist und dementsprechend beibehalten werden muss? Dies ist etwas, das mit Code erzwungen werden muss, ist nicht mit der Swift-Sprache allein möglich.

Es klingt, als ob Sie versuchen, eine Art Modellobjektdiagramm zu erstellen, was ein Problem ist, das viele Male gelöst wurde. Sie sollten einen Blick auf Realm DB und Core Data werfen, die beide verwaltete bidirektionale Beziehungen bieten. Sie werden jedoch feststellen, dass keines davon mit Strukturen implementiert ist. Das Problem bei der Verwendung von Werttypen besteht darin, dass es sich beim Kopieren um Schreiben handelt. Sobald Sie eine Struktur im Objektdiagramm mutieren, müssten Sie alle zugehörigen Dinge der neuen, mutierten Kopie neu zuweisen, die dann wiederum mutiert sind und alle ihre verwandten Strukturen aktualisieren müssten. Referenzsemantiken (Klassen) erleichtern die Pflege eines Objektgraphen, da Mutationen keine neuen Instanzen erzeugen.

+0

stimme voll und ganz zu, was du sagst. obwohl ich Core-Daten oder Bereich nicht besonders brauche, da beide in erster Linie Persistenz-Layer sind (was mir hier nicht wirklich wichtig ist), der Punkt, dass sie beide die bidirektionale Beziehung implementieren, indem sie Klassen anstelle von Strukturen verwenden, ist definitiv gültig! – nburk

+0

danke für die Bearbeitung, das macht es noch deutlicher! – nburk

+0

@nburk Froh, zu helfen. Core Data kann auch als Speichergrafik mit 'NSInMemoryStoreType' verwendet werden. Sie sind beide noch immer stark als Objektgraph-Manager, abgesehen von der Beharrlichkeit. –

2

Was Sie wollen, ist nicht möglich mit Strukturen. Ihre aktuelle Lösung (mit var) funktioniert nicht so, wie Sie es denken: Alle Werte sind unabhängige Kopien. Betrachten Sie das folgende Beispiel:

let p = Person(name: "Nick", houses: []) 
let h = House(owner: p) 
h.owner.houses 
p.houses 

Da jede Kopie unabhängig ist, bedeutet dies, p nicht das gleiche wie h.owner ist.

Wenn Sie eine bidirektionale Beziehung benötigen, sollten Sie Objekte mit weak Zeigern verwenden (um den Referenzzyklus zu unterbrechen). Alternativ könnten Sie überlegen, ob Sie die bidirektionale Beziehung benötigen.

+0

Ich entschied mich für das Entfernen der Voraussetzung für die gegenseitige Verbindung zwischen den Objekten, da ich wirklich nur experimentieren möchte und maximieren Sie die Verwendung von Werttypen in meinem Code, um zu sehen, wo ich auf Probleme mit diesem Ansatz stoße. Danke für die Hilfe !! – nburk

Verwandte Themen