Dictionary - Werte im Array ändern

  • Dictionary - Werte im Array ändern

    Ich habe (wieder mal) ein Array aus Dictionarys.

    Ich lese dieses testweise ein und überprüfe die richtige Zuweisung :

    Quellcode

    1. var txt : String = (selectedDyes.objectAtIndex(0).valueForKey("name") as! String)
    2. NSLog("Name = %@", txt)

    Der Log bestätigt, dass der richtige Produktname gespeichert ist. Es erscheint : "Name = alter Name"

    Wenn ich diesen Namen nun ändern möchte - so dachte ich bisher - ersetze ich das Key-Value-Paar mittels
    xxx.setObject(<value: AnyObject?>, forKey: <String>)


    Quellcode

    1. selectedDyes[0].setValue("Neuer Name", forKey: "name")
    Der Erfolg ist eine Fehlermeldung :


    Compiler-Meldung schrieb:

    2016-02-19 13:51:56.292 Fastness Calculator[7984:1049601] -[_TtGCSs29_NativeDictionaryStorageOwnerSSPSs9AnyObject__ setObject:forKey:]: unrecognized selector sent to instance 0x60000002e660
    Kann mir jemand sagen, was hier falsch ist?
  • HansGerber schrieb:

    Ich habe (wieder mal) ein Array aus Dictionarys.

    Ich lese dieses testweise ein und überprüfe die richtige Zuweisung :

    Quellcode

    1. var txt : String = (selectedDyes.objectAtIndex(0).valueForKey("name") as! String)
    2. NSLog("Name = %@", txt)
    Der Log bestätigt, dass der richtige Produktname gespeichert ist. Es erscheint : "Name = alter Name"

    Wenn ich diesen Namen nun ändern möchte - so dachte ich bisher - ersetze ich das Key-Value-Paar mittels
    xxx.setObject(<value: AnyObject?>, forKey: <String>)


    Quellcode

    1. selectedDyes[0].setValue("Neuer Name", forKey: "name")
    Der Erfolg ist eine Fehlermeldung :


    Compiler-Meldung schrieb:

    2016-02-19 13:51:56.292 Fastness Calculator[7984:1049601] -[_TtGCSs29_NativeDictionaryStorageOwnerSSPSs9AnyObject__ setObject:forKey:]: unrecognized selector sent to instance 0x60000002e660
    Kann mir jemand sagen, was hier falsch ist?
    Ohne wirkliche Ahnung von swift zu haben, aber das klingt mir sehr danach, als würde es sich um ein NSDictionary statt einem hierfür nötigen NSMutableDictionary handeln?
  • HansGerber schrieb:

    Wenn ich diesen Namen nun ändern möchte - so dachte ich bisher - ersetze ich das Key-Value-Paar mittels
    xxx.setObject(<value: AnyObject?>, forKey: <String>)


    Quellcode

    1. selectedDyes[0].setValue("Neuer Name", forKey: "name")
    Der Erfolg ist eine Fehlermeldung :


    Compiler-Meldung schrieb:

    2016-02-19 13:51:56.292 Fastness Calculator[7984:1049601] -[_TtGCSs29_NativeDictionaryStorageOwnerSSPSs9AnyObject__ setObject:forKey:]: unrecognized selector sent to instance 0x60000002e660
    Kann mir jemand sagen, was hier falsch ist?

    Die Fehlermeldung sagt, daß Du ein natives Swift Dictionary hast und kein NSDictionary, bzw. NSMutableDictionary. Swift Dictionaries haben von Haus aus die Methode setValue... nicht implementiert.

    Drei Möglichkeiten:

    1.) Du definierst Dein Array anders. z.B. Array<NSMutableDictionary> oder so ähnlich

    2.) Du castest. (array[0] as! NSMutableDictionary).setValue... oder so ähnlich

    3.) Du machst die Zuweisung einfach auf die Swiftweise: array[0]["name"] = newValue

    Edit: Mit #2 selber einmal experimentiert. Das geht nicht. Ein Swift Dictionary kann zu NSDictionary gecastet werden, nicht aber zu einem NSMutableDictionary.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von torquato ()

  • Du hast da aber auch einen ganz schönen Typenmischmasch angezettelt... ;)

    Wie erklär ich's?

    Es liegt an der Verschachtelung und dem AnyObject. Letzteres hatte @macmoonshine in einem anderen Thread von Dir schon mal herausgestellt. Array und Dictionary sind in Swift als structs deklariert. AnyObject verlangt aber zwingend ein Klassenobject. Swift ist jetzt 'clever' und wandelt die Swift struct in den passenden Cocoa Datentypen um, der ein Klassenobjekt ist, NSArray, bzw. NSDictionary. Das Dumme ist nur, daß die, im Gegesatz zum Swift-Gegenpart, unveränderlich sind...

    Das gleiche passiert übrigens auch in Deinem eingangs zitierten Code, wo der Value ein String sein soll. Da wird fleißig und unnötigerweise zwischen Swift Strings und NSString hin- und hergecastet.

    Ich sehe zwei Möglichkeiten:

    1.) Du fängst nochmal weiter vorne an und benutzt von Anfang an die richtigen Swift-Typen, z.B. Array<[String : Any]>. Any umfaßt auch die Swift-Wertetypen wie Int und Dictionary. Oder

    2.) Du verzichtest komplett auf die Swift-Collection-Types und benutzt von vorne herein nur NSMutableArray und NSMutableDictionary. Das ist durchaus möglich.

    Nr. 2 ist zwar nicht so 'swiftish', aber würde Dir wahrscheinlich leichter fallen...
  • @tsunamix : Weg 2 hat funktioniert!
    Die ganzen Swift Arrays und Dictionaries durch NSMutableXXX ersetzt und schreiben und ersetzen sind endlich möglich.

    So mühsam das ganze war. so lehrreich war es aber auch zu sehen, dass beim Casting das Mutable gerne mal auf der Strecke bleibt.

    Danke nochmals!
    Hans

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von HansGerber ()

  • Eine Anschlussfrage hat sich ergeben, die mit Kopien von Referentypen zu tun hat:

    1) Ich habe eine Gesamtliste AllDyes, die in einem Outlineview dargestellt wird
    2) Durch Klicken wähle ich aus dieser Gesamtliste Elemente aus (-> selectedDyes)

    Quellcode

    1. func outlineViewSelectionDidChange(notification: NSNotification) {
    2. var selected : NSIndexSet
    3. var first : Int
    4. //Rücksetzen vor jeder Neuselektierung
    5. selectedDyes.removeAllObjects()
    6. selected = outlineview.selectedRowIndexes
    7. first = selected.firstIndex
    8. for _ in selected {
    9. if first != NSNotFound && selected.count <= 8 {
    10. selectedDyes.addObject((outlineview.itemAtRow(first)?.representedObject)!)
    11. first = selected.indexGreaterThanIndex(first)
    12. }
    13. }
    14. ....
    Alles anzeigen

    Mit diesem Ansatz funktioniert nun endlich das Anpassen des selectedDyes-Arrays.

    ABER : jede Änderung hier hat natürlich auch Auswirkung auf das AllDyes-Array, sind ja die gleichen Objekte referenziert.
    Wie mache ich eine "unabhängige" Kopie (deep copy?), so dass :

    Quellcode

    1. selectedDyes.objectAtIndex(0).setValue("Neuer Name", forKey: "name")
    nur Auswirkungen auf selectedDyes und nicht auch auf AllDyes hat?

    Ich habe .copy() versucht, bekomme dann allerdings ein AnyObject zurück, das ich wieder nicht per "setValue forKey" bearbeiten kann.
  • Ein Deepcopy musst du über mutableCopy selber bauen. Diese Methode macht aber kein Deep-Copy; d. h. du musst deinen Objektbaum selber durchlaufen und kopieren.

    HansGerber schrieb:

    Ich habe .copy() versucht, bekomme dann allerdings ein AnyObject zurück, das ich wieder nicht per "setValue forKey" bearbeiten kann.
    Das ist ja auch nicht die Aufgabe von copy. Das erzeugt nämlich immer unveränderliche Objekte.
    „Meine Komplikation hatte eine Komplikation.“
  • Perfekt! Das funktioniert:

    Quellcode

    1. for _ in selected {
    2. if first != NSNotFound && selected.count <= 8 {
    3. var cpy = (outlineview.itemAtRow(first)?.representedObject)!.mutableCopy()
    4. selectedDyes.addObject(cpy)
    5. //selectedDyes.addObject((outlineview.itemAtRow(first)?.representedObject)!)
    6. first = selected.indexGreaterThanIndex(first)
    7. }
    8. }