Class in Swift / SwiftUI - Habe ich das Konzept richtig verstanden?

D

duras

Aktives Mitglied
Thread Starter
Dabei seit
02.09.2008
Beiträge
277
Reaktionspunkte
27
Hallo zusammen,

Ich habe vor 3 Wochen mir Swift / SwiftUI angefangen und das ein oder andere Übungsprojekt relativ erfolgreich angegangen. Aktuell hänge ich jetzt aber seit mehreren Tagen an einem Punkt und komme nicht weiter. Vielleicht könnt ihr mir da helfen.

Soweit ich Klassen in Swift verstehe, kann ich von einer Klasse beliebig viele Instanzen haben, wenn ich an einer beliebigen Instanz einen Wert verändere übernehmen alle anderen Instanzen diesen Wert auch. Im Playground klappt das auch wunderbar:
Diff:
struct this {
    var a = "A"
    var b = "B"
    var c = "C"
    mutating func changeB() {
        self.b = "E"
    }
}

class that {
    var a = "A"
    var b = "B"
    var c = "C"
    func changeB() {
        self.b = "E"
    }
}

var thisVar = this()
let thisVarCopy = thisVar
thisVar.a = "D"
thisVar.changeB()

let thatVar = that()
let thatVarCopy = thatVar
thatVar.a = "D"
thatVar.changeB()

print("This Var -> \(thisVar.a).\(thisVar.b).\(thisVar.c)\n")
// This Var -> D.E.C

print("This Var Copy -> \(thisVarCopy.a).\(thisVarCopy.b).\(thisVarCopy.c)\n")
// This Var Copy -> A.B.C

print("That Var -> \(thatVar.a).\(thatVar.b).\(thatVar.c)\n")
// That Var -> D.E.C

print("That Var Copy -> \(thatVarCopy.a).\(thatVarCopy.b).\(thatVarCopy.c)\n")
// That Var Copy -> D.E.C

Prima - alles wie erwartet.

Nun versuche ich gerade, eine Dokumenten-Basierte App für MacOS zu schreiben. In Xcode erstelle ich dafür ein neues Projekt, wähle Dokumenten-Basiert aus, und SwiftUI als Oberfläche.

in der von Xcode generierten Document-Class füge ich ein Property hinzu (und mache die Class konform zu Observable-Object)
Code:
    @Published var content = "Start string"

Als Test habe ich dann noch in der init() dem content einen neuen Wert zugewiesen:
Code:
 self.content = "Initialized string"

und die Save-Methode entsprechend angepasst:
Code:
return content.data(using: .utf8) ?? Data()

Wenn ich das Projekt jetzt starte und speichere (reines Textfile) bekomme ich wie zu erwarten ein Textfile mit "Initialized string" (oder, wenn ich die entsprechende Zeile auskommentiere "Start String"). Soweit auch noch gut.

Jetzt will ich die Daten aber natürlich auch vom User verändern lassen. In meiner ContentView mache ich also ein Textfeld, ein Button und ein String - und erstelle die entsprechenden Propertys:
Swift:
struct ContentView: View {
  
    @ObservedObject var document = Document()
    @State var textFieldString = "TextFieldString"

    var body: some View {
        VStack {
            TextField("Placeholder", text: $textFieldString)
                .frame(maxWidth: .infinity)
            Button(action: { self.document.content = self.textFieldString
                print("I want to change the string")

            } ) {
                Text("Click me")
            }
            Text("\(document.content)")
        }
    }
}
Beim starten ist das TextField dann mit "TextFieldString" gefüllt, der Text unten steht auf "Initialized string" bzw. "Start string".
Drücke ich also den Button, wird der Text unten geupdated und der Inhalt des TextFields steht nun dort. Soweit auch noch logisch. Die Konsole gibt auch "I want to change the string" aus

Nun zum Großen ABER:
Speichere ich das Dokument jetzt, ist in der gespeicherten Textdatei trotzdem nur "Start string" oder "Initialized string" - niemals aber der Wert, den ich vorher mittels Button-Click in die document.content geschrieben habe.

Jemand nen entsprechenden Hinweis, was ich falsch mache? Ich verzweifle hier langsam...

Liebe Grüße
Duras
 
Nur vom Querlesen und mit dem ausdrücklichen Hinweis, dass ich kein Swift-Programmierer bin:
Du erzeugst m.E. mit
Code:
var document = Document()
eine neue Instanz vom Typ Document, der du dann in der Aktion den Eingabewert zuweist.
Ich habe jetzt nicht gesehen, dass das dein "Originaldokument" ist, d.h. ich vermute, du speicherst eine andere Instanz, als du veränderst.
Und auch dein Statement hier weist darauf hin, dass du dieses Thema nochmal vertiefen solltest:
Soweit ich Klassen in Swift verstehe, kann ich von einer Klasse beliebig viele Instanzen haben, wenn ich an einer beliebigen Instanz einen Wert verändere übernehmen alle anderen Instanzen diesen Wert auch.
Nö, es ist ja der Sinn der Instanz, dass sie eigene Properties hat.... Nur das "Verhalten" ist gleich (also die Methoden, die Anzahl der Properties..) zumindets vereinfacht ausgedrückt.
Also:
- mir fehlt das Binden / Übergeben des vermutlich beim Start der App initial erzeugten "document" an die Aktion...
- früher (locker 10 Jahre) hab ich mal mit ObjC rumgespielt, da konnte man bei einer "document based app" oder wie das hieß, das "Dokument" einfach auf den Controller ziehen und hatte es dann direkt im Zugriff

Aber wie gesagt: nur ne Idee, habe mit Swift noch nicht gearbeitet...
 
  • Gefällt mir
Reaktionen: duras
Moin,
jetzt schnell in der Mittagspause überflogen fällt mir auf, dass du doch gar nicht in die Textdatei speicherst sondern nur den document.content neu zuweisen tust.
Wie sieht denn deine Speichern-Methode aus?
 
  • Gefällt mir
Reaktionen: duras
var thisVar = this()
let thisVarCopy = thisVar

Die erste Zeile erzeugt eine neue Instanz. Die zweite Zeile erzeugt eine neue Referenz auf die selbe Instanz.

Soweit ich Klassen in Swift verstehe, kann ich von einer Klasse beliebig viele Instanzen haben, wenn ich an einer beliebigen Instanz einen Wert verändere übernehmen alle anderen Instanzen diesen Wert auch.

Du verwechselst Instanz und Referenz.
 
  • Gefällt mir
Reaktionen: duras
Nö, es ist ja der Sinn der Instanz, dass sie eigene Properties hat.... Nur das "Verhalten" ist gleich (also die Methoden, die Anzahl der Properties..) zumindets vereinfacht ausgedrückt.
Ja, danke. Ich hab mittlerweile schon mit nem Kollegen gequatscht, der C programmiert hat und er hat mich schon auf die falsche Denkweise hingewiesen.

- mir fehlt das Binden / Übergeben des vermutlich beim Start der App initial erzeugten "document" an die Aktion...
- früher (locker 10 Jahre) hab ich mal mit ObjC rumgespielt, da konnte man bei einer "document based app" oder wie das hieß, das "Dokument" einfach auf den Controller ziehen und hatte es dann direkt im Zugriff.
zum ersten Punkt: Ja, mir auch 😭 genau das ist ja mein Problem :D
Das mit dem "Drag and Drop" funktioniert, wenn man mit Swift und Storyboards arbeitet - ich will aber Swift und SwiftUI - und dabei habe ich noch keinen Weg gefunden.
Vielleicht versuche ich es aber nochmal mit dem Storyboard - ganz rudimentär - und versuche, dass was der dann da erzeugt auf meinen Fall umzustricken.

jetzt schnell in der Mittagspause überflogen fällt mir auf, dass du doch gar nicht in die Textdatei speicherst sondern nur den document.content neu zuweisen tust.
Wie sieht denn deine Speichern-Methode aus?
Die Speichern-Methode ist von der NSDocument-Klasse, dort werfe ich mittels
Swift:
return content.data(using: .utf8) ?? Data()
einfach die Variable rein (content) und die wird dann in das Textdokument geschrieben. Das funktioniert ja auch, lediglich nimmt er immer die Werte aus dem Model - nicht die aus der Instanz die ich habe.
Zwischenzeitlich habe ich es mit einem Singleton-Statement gelöst, das hat aber den Nachteil, dass wenn ich mehrere Dokumente geöffnet habe alle Synchronisiert werden, weil sie sich natürlich alle die globale Instanz teilen. Ich brauche also eine Instanz pro geöffnetem Dokument (wahrscheinlich in der App-Delegate wie ruerueka sagte...), und muss dann noch irgendwie rausfinden, wie ich die immer beim speichern passend an die Speichern-Methode übergebe.


Die erste Zeile erzeugt eine neue Instanz. Die zweite Zeile erzeugt eine neue Referenz auf die selbe Instanz.
Du verwechselst Instanz und Referenz.
Siehe Oben - Fehler schon erkannt ;)
 
  • Gefällt mir
Reaktionen: stepi0
Kurzes Update und Sorry für Doppelpost.

Ich habe heute dann auch festgestellt, dass man die Document-based app und Core Data kombinieren kann. Das löst viele Probleme, das Template was Xcode einem da gibt sieht auch deutlich verständlicher aus. Ausserdem kommt das dann direkt mir UnDo/Redo-Manager und Versionierung der Dateien - also genau so, wie man es von Pages/Numbers etc. gewöhnt ist. Insofern ist mein Hauptproblem jetzt erstmal gelöst :)

Jetzt muss ich nochmal ein bisschen tiefer in die Core Data Materie gehen, aber das ist wohl ein anderes Thema :)
 
  • Gefällt mir
Reaktionen: ruerueka
Zurück
Oben Unten