Zuweisung, irgendwas ist da komisch

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Aufgrund der Corona-Krise: Die Veröffentlichung von Stellenangeboten und -gesuchen ist bis 31.12.2020 kostenfrei. Das beinhaltet auch Angebote und Gesuche von und für Freischaffende und Selbstständige.

  • Zuweisung, irgendwas ist da komisch

    Hallo Zusammen,

    ich habe da eine komische Sache, vielleicht hat jemand einen Tipp...

    zuerst habe ich ein struct/class (whatever) mit folgender Definition:

    Quellcode

    1. struct MyStruct {
    2. var id: UUID?
    3. //...
    4. }

    sollte ja funktionieren, in Rat und Tat schlägt auch der Compiler keinen Alarm

    Dann habe ich auch noch ein wunderbares CoreData Objekt mit folgender Definition:

    Quellcode

    1. @objc(TMyRec) public class TMyRec: NSManagedObject {
    2. @NSManaged public var id: UUID?
    3. //...
    4. }
    Auch das meckert der Compiler nicht an. In Rat und Tat meckert er gar nicht, an gar keiner Stelle... :whistling:

    Beim Speichern nach CoreData, wird da auch wunderbar was gespeichert. Es wird auch wunderbar der gleiche Record Wiede rückgeliefert <!!!Heureka!!!>

    Die Objekte möchte ich in ein Array of MyStruct ablegen um die Referenz auf CoreData zu verlieren und den Fingerprint gering zu halten (wird nur noch zur Auswertung benötigt.

    Dafür wird ein grandioses Array definiert, das wie folgt aussieht:

    Quellcode

    1. var myStructs = [MyStruct]()
    Nachdem der Record von der Datenbank eingelesen wurde, möchte ich diesen in dem Array speichern...
    Dazu lege ich mal eine lokale Variable an:

    Quellcode

    1. var newRec = MyRec()
    Dann übertrage ich die Werte von CoreData nach NewRec

    Quellcode

    1. newRec.id = myRecFromDB.id
    Die Variable aus MyStruct.Id habe ich mit einen Setter versehen und der gibt beim Übertagen folgendes aus:

    Quellcode

    1. Wert zu setzen: Optional(2BE6A2FA-2802-45BE-93B2-FFF168488152)
    2. Gesetzter Wert: Optional(2BE6A2FA-2802-45BE-93B2-FFF168488152)
    3. (lldb)
    Soweit, so gut...

    Doch, wenn ich auf das Objekt schaue, ist der Wert von Id noch unverändert und wird wie folgt ausgegeben:

    Quellcode

    1. id = (UUID?) nil
    Das heisst, er wird zwar irgendwie Übertagen, kommt auch an, aber auch nicht an...

    Hatte einer eine Idee, wo es hängen könnte?

    Scheint als das Objekt irgendwie ReadOnly wäre, ohne dass der Compiler meckert... was aber nicht sein kann...

    Was noch hinzukommt: gibt es in dem selben Record auch noch Variablen die Korrekt gesetzt werden. Nur bei manchen funktioniert die Übertragung nicht...

    Nachtrag: Auch beim direkten setzen von

    Quellcode

    1. newRec.id = UUID()
    wird zwar der Wert unter newRec.id fortgeschrieben, doch der Wert im Record bleibt dennoch unverändert.

    <DerRatloseWolf>

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von Wolf () aus folgendem Grund: Startstruktur verloren gegangen

  • Hallo MCDan,

    vermute ich leider nicht, ich hatte noch einen Nachtrag geschrieben. Die Objekte werden über einen normalen FetchRequest aus der DB erzeugt nach folgenden Schema:

    Quellcode

    1. if let matches = try? managedContext.fetch(request), matches.count > 0 {
    2. return matches
    3. }
    4. //Sonst leeres Array zurückgeben
    5. return []
    Im Nachtrag hatte ich noch erwähnt, dass es selbst bei der direkten Zuweisung keine Änderung im Objekt/Struct gibt, obgleich die Zuweisung erfolgt. Irgendwas klemmt...

    PS: O.k. kann man noch etwas performanter machen, das mit .count ist nicht ganz optimal...

    Schöne Grüsse
    Wolf
  • Tja, die Value Types gibt's bei den structs, die class sind Referenztypen.

    Sind ja nur ein paar Klicks, das entsprechend umzustellen, wurde auch gemacht, leider mit dem selben Ergebnis.

    Wie im Nachtrag geschrieben, ist das Verhalten auch noch bei dem folgenden Code nachzuvollziehen:


    Quellcode

    1. var newRec = MyRec() //bei struct
    2. let newRec = MyRec() //bei class
    3. newRec.id = UUID() //und direkter Zuweisung.
    4. //Das ist eigentlich gar nicht möglich
    5. //und falls nicht veränderbar, meckert normal der Compiler...
    6. //ist aber hier nicht der Fall
    Das heisst zusammen gefasst, class/struct Definition plus dieser Quellcode ist der zusammenhängende Code.

    //Eigentlich vollkommen unlogisch :(

    Schöne Grüsse
    Wolf

    PS: Die lange Einleitung resultierte daher, dass ich noch dachte, dass es einen Zusammenhang mit CoreData hätte. Von dem muss ich mich gerade verabschieden.
  • Ich verstehe dein Problem aber immer noch nicht. Der folgende Code

    Quellcode

    1. struct MyStruct {
    2. var id: UUID?
    3. }
    4. class MyClass {
    5. var id: UUID?
    6. }
    7. var theStrukt = MyStruct()
    8. let theClass = MyClass()
    9. dump(theStrukt)
    10. dump(theClass)
    11. theStrukt.id = UUID()
    12. theClass.id = UUID()
    13. dump(theStrukt)
    14. dump(theClass)
    Alles anzeigen

    gibt folgendes aus:

    Quellcode

    1. ▿ __lldb_expr_1.MyStruct
    2. - id: nil
    3. ▿ __lldb_expr_1.MyClass #0
    4. - id: nil
    5. ▿ __lldb_expr_1.MyStruct
    6. ▿ id: Optional(5A002CAA-D1E8-4A29-AF02-A836098D4B28)
    7. - some: 5A002CAA-D1E8-4A29-AF02-A836098D4B28
    8. ▿ __lldb_expr_1.MyClass #0
    9. ▿ id: Optional(951127D6-DE04-4C51-8836-74D00B2E65E0)
    10. - some: 951127D6-DE04-4C51-8836-74D00B2E65E0
    Was ist daran jetzt komisch?
  • Michael schrieb:

    Was ist daran jetzt komisch?

    Tja, weil er es bei mir eben nicht macht und zwar weder bei dem struct noch bei der class. Das ist ja das komische. Er bringt auch keine Fehlermeldung, dass er einen Schreibschutz hätte...

    Muss mal weiter suchen, vielleicht finde ich doch noch was oder das ganze geht einfach nach ein paar Tagen wieder, wie schon ein paar Mal vorgekommen.

    Schöne Grüsse
    Wolf
  • Brauchst Du die extra id wirklich? - Könnte mir gut vorstellen, dass Du die objectID von NSManagedObject.

    Wolf schrieb:

    Die Objekte möchte ich in ein Array of MyStruct ablegen um die Referenz auf CoreData zu verlieren und den Fingerprint gering zu halten (wird nur noch zur Auswertung benötigt.
    Das klingt nach Optimierung. Diese ist erst nötig, falls ein Problem auftritt. Auch kann man seinen Code anders organisieren. Nicht all 100.000 Einträge rausholen, sondern nur 1.000 Einträge, diese verarbeiten, dann die nächsten 1.000 Einträge usw.. Keine Ahnung, welche Aggregate Functions Core Data besitzt. Vllt. kann auch Core Data zum Teil deine Auswertung machen.
  • Ich hatte mich zufrüh gefreut. Das Problem ist nach wie vor da. Aber ganz komisch...

    Lass ich mir die Struktur im Code via dump() ausgeben, ist alles so, wie es sein soll . Einfach wunderbar :)

    Schau ich mir die selbe Struktur dann im Debugger an, (an der selben Stelle) fehlen aber bei verschiedenen Feldern der Struktur die Werte an einigen Stellen. Das wäre jetzt insgesamt nicht so tragisch, doch leider brauche ich die Felder im Anschluss wieder, deswegen hatte ich mit asset() eine Validieren eingebaut, an der Stelle wo ich die Werte benötige und die schlägt leider unbarmherzig zu. Das heisst, es ist nicht nur alleine ein Darstellungsfehler vom Debugger, sondern er überträgt die Werte dann auch nicht wirklich.

    Da die Daten zu diesem Zeitpunkt bereits von CoreData entkoppelt sind, hat es sicher nichts mehr mit CoreData zu tun.

    Meist betrifft es die Fehler die mit einer UUID? oder Date? definiert wurden. Sind auch immer die selben Felder...

    Die records werden aus einen Array wie folgt gelesen...


    Quellcode

    1. for r in myArrayFullOfRecords {
    2. dump(r) //alles in Ordnung
    3. //Im Debugger fehlt die Hälfte
    4. ...
    5. }
    hat einer eine Idee?

    Schöne Grüsse
    Wolf
  • manoh schrieb:


    Das klingt nach Optimierung.
    Eher weniger, das ist eine Lehre aus der ersten Zeit mit SwiftUI, das bekommt es öfters nicht korrekt mit und so habe ich mir angewöhnt, das ganze selbst in der Hand zu halten und die Aktualisieren des Bildschirms zu steuern.

    Mit Aggregatren geht das hier leider nicht, es sind doch recht komplexe Berechnungen und Umlagen mit verschiedenen Kursen nötig. Diese sollen on the fly berechnet werden. Rechne vielleicht mal bis zu 10'000 Datensätze maximal. Das schafft die Kiste locker.

    Schöne Grüsse
    Wolf
  • So, einen Bug hab ich zumindest gefunden. Das Problem dabei ist nur, dass es bei manchen Records funktioniert hat und bei anderen ist er auf die Bretter gegangen....
    ... hätte so nicht sein dürfen. Hier mal ein wenig Code...

    Quellcode

    1. class Leaf {
    2. var a: String?
    3. func clear() {
    4. a = nil
    5. }
    6. }
    7. struct Knot {
    8. var b: Int?
    9. var leaf: Leaf?
    10. init() {
    11. b = nil
    12. leaf = Leaf()
    13. clear()
    14. }
    15. mutating func clear() {
    16. b = nil
    17. leaf = nil
    18. }
    19. }
    20. for r in myWonderfullRecords {
    21. dump(r) //freu
    22. let k = Knot()
    23. k.leaf?.a = r?.a //Zuweisen sollte doch funktionieren
    24. ...
    25. dump(k) //grosses Staunen
    26. }
    Alles anzeigen
    Schöne Grüsse
    Wolf
  • Wolf schrieb:

    Quellcode

    1. k.leaf?.a = r?.a //Zuweisen sollte doch funktionieren
    Heißt das, dass myWonderfullRecords ein Array von Leaf? ist?

    Welche Erwartungshaltung hast Du bei dieser Zuweisung. Also wenn r = Nil, r.a = Nil und r = ""?

    Müssen eigentlich die ganzen Optinals sein? Und wenn man eine Erwartungshaltung hat, dann würde ich guard vorziehen und nicht Optional Chaining. Da kannst Du dann im else-Zweig eine Fehlermeldung ausgeben oder einen Fehler schmeißen.

    Wolf schrieb:

    stimmt, das ist eine Lösung.
    clear() und init(): man könnte das so programmieren, dass clear() das Objekt so herstellt wie nach einem init(). Nur so ein Gedanke.
  • Ich mag eigentlich überhaupt keine Optionals, nur wenn ich eine Feldbeschreibung im CoreData Editor eingebe, kann ich keinen Initialwert für die UUID setzen, daher musste ich die UUID? definieren. Das hat dazu geführt, dass ich irgendwann mal das ganze einheitlich haben wollte und dann wurden halt mehr Optionals draus ;)

    Mit Optional Channing läuft das halt alles so smouth ab, kein Fehler, kein Programmabbruch... fantastisch :)

    Dann hatte ich doch bedenken und hab dann ein paar asserts() eingebaut. Mit der Folge, dass es ständig nur gekracht hat... O.k. hätt ich auch mit Guard machen können.

    Aktuell hab ich es jetzt am laufen :)

    Das letzte Problem war, dass beim WheelPicker, nachdem die Grundlage verändert wurde, nicht der richtige Wert gesetzt wurde. Der WheelPicker hat mir unter SwiftUI schon einige graue Haare gekostet. Hoffen wir mal, das es unter SwiftUI 2.0 besser wird.

    Schöne Grüsse
    Wolf