NSString ECHTE Kopie

  • Das kann vielleicht an Deinen speziellen NSStrings liegen, da NSString ein 'class-cluster' ist.
    Entweder Du probierst ein '-mutableCopy' oder '-initWithString:'.
    Bei der zweiten Methode verspricht die Doku, dass Dein String kopiert wird.
    I would be embarrassed if they did not spy on me.
  • Hi,

    das mutableCopy funktioniert, nur habe ich dann einen NSMutableString. Wenn ich ihn wieder zurückwandel habe ich leider wieder dieselbe Speicheradresse:

    Quellcode

    1. NSString *bundleIdentifier = [pasteboardItem stringForType:bundleIdentifierPasteboardType];
    2. NSMutableString *mutableBundleIdentifier = [bundleIdentifier mutableCopy];
    3. bundleIdentifier = [NSString stringWithString:mutableBundleIdentifier];
    4. NSLog(@"%p", bundleIdentifier);
    5. NSLog(@"%p", mutableBundleIdentifier);
    6. NSLog(@"%p", bundleIdentifier);


    und der output:

    0x2000c8160
    0x200014220
    0x2000c8160

    Gruss,
    Johannes
  • Was ist Dein Ziel, warum leider?
    Warum soll der String doppelten Speicher belegen? Er ist konstant, und das System "weiss" das.

    Das "+stringWithString:" das sogar zurück schraubt, wäre ich so nicht darauf gekommen, ist aber nur konsequent.

    Was macht denn:

    Quellcode

    1. bundleIdentifier = [NSString stringWithString:[mutableBundleIdentifier copy]];
    I would be embarrassed if they did not spy on me.
  • Hi,

    das Problem ist, das ich die Strings anhand ihrer Speicheradresse unterscheiden muss. Obwohl Sie den gleichen Inhalt haben müssen, gibt es einen "alten" und einen "neueen" String. Das geht eben nur mit 2 Objekten.

    Quellcode

    1. bundleIdentifier = [NSString stringWithString:[mutableBundleIdentifier copy]];


    Das wird wohl nichts ändern, mutableBundleIdentifier hat ja schon eine andere Speicheradresse als bundleIdentifier.

    Gruss,
    Johannes
  • Original von johannesauer
    Hi,

    das Problem ist, das ich die Strings anhand ihrer Speicheradresse unterscheiden muss. Obwohl Sie den gleichen Inhalt haben müssen, gibt es einen "alten" und einen "neueen" String. Das geht eben nur mit 2 Objekten.


    Aber wenn der Inhalt gleich ist, dann brauch man ja wie gesagt den String nicht 2 mal im Speicher, das macht schon Sinn. Ich weis ja nicht wie du die, Strings weiterverarbeitest, bzw. wozu du eine 1 zu 1 Kopie brauchst.
    Chris
  • Hi,

    das Problem ist folgendes:

    Ich stopfe einen String in ein Array auf einen nicht bekannten index, dann kopiere ich den String und stopfe die Kopie wieder in das Array. Jetzt möchte ich den index des ersten Strings wissen um es entfernen zu können. Dazu brauche ich zwei echt verschiedene strings, sonst ist es zufall, ob der erste string oder die Kopie rausfliegt. Klingt alles ein wenig sinnlos, erfüllt aber einen zweck ;)

    Das Problem ist das Cocoa davon ausgeht, das nur der Inhalt, nicht aber die Speicheradresse von Bedeutung sein könnte.

    Gruss,
    Johannes
  • Original von johannesauer
    Hi,

    das Problem ist folgendes:

    Ich stopfe einen String in ein Array auf einen nicht bekannten index, dann kopiere ich den String und stopfe die Kopie wieder in das Array. Jetzt möchte ich den index des ersten Strings wissen um es entfernen zu können. Dazu brauche ich zwei echt verschiedene strings, sonst ist es zufall, ob der erste string oder die Kopie rausfliegt. Klingt alles ein wenig sinnlos, erfüllt aber einen zweck ;)

    Das Problem ist das Cocoa davon ausgeht, das nur der Inhalt, nicht aber die Speicheradresse von Bedeutung sein könnte.

    Gruss,
    Johannes

    Das hängt damit zusammen, dass Cocoa etwas mit OOP zu tun hat. Wieso sollte es interessieren, wo sich ein Objekt befindet? Es hat eine API. Die mag man nutzen oder nicht. Ich würde daher auch noch einmal das Design überdenken.

    Zurück zum Thema, wieso merkst du dir nicht den String, entfernst ihn zunächst aus dem Array und fügst ihn dann ein?

    Quellcode

    1. NSString* stringToMove = [[theString retain] autorelease];
    2. [theArray removeObject:theString];
    3. [theArray insertObject:theString atIndex:index];


    Oder wieso merkst du dir nicht vorher den Index?

    Quellcode

    1. NSString* stringToMove = [[theString retain] autorelease];
    2. NSUInteger oldIndex = [theArray indexOfObject:theString];
    3. [theArray insertObject:theString atIndex:index];
    4. [theArray removeObjectAtIndex:oldIndex];
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • 1. ein NSMutableString ist auch ein NSString (d.h. mutableCopy ist nicht schlimm)
    2. NSArray hat die Methode -indexOfObjectIdenticalTo: die nicht nach Inhalt sondern Speicheradresse vergleicht

    Aber ich halte den Ansatz trotzdem für seltsam. Bei einem ordentlichen Design würde man ein Wrapper-Objekt definieren, das den (möglicherweise gleichen) Inhalt speichert sowie ein Unterscheidungskriterium. D.h. "der erste String abc", "der zweite String abc".

    Dann würde man -copy so implementieren, dass man ein neues Objekt der Wrapperklasse bekommt der den identischen String referenziert (Speicher sparen), aber die "Nummer" verändert.

    Vielleicht beschreibst Du den Zweck besser (GUI?). Dafür gibt es oft viel bessere Lösungen.

    -- hns
  • Hallo,

    erstmal danke für eure Antworten!
    Am besten erkläre ich kurz nochmal den Ansatz, dann versteht man auch das Problem besser:

    Es geht um drag & drop in einer tableview. Es soll möglich sein, beliebig viele rows anzufassen und diese an eine neue position zu verschieben. Dazu kopiere ich die selektierten rows in das pasteboard und speichere die speicheradressen in einem globalem (intantzvaribale) array. Wenn der drop ausgeführt wird passiert folgendes:

    1. Die Objekte werden der Reihe nach an der entsprechenden Stelle in die Tableview (bzw deren array) eingefügt. Das klappt wunderbar, nur haben wir jetzt alle gedroppten objekte doppelt, sie wurden ja zum array der tableview hinzugefügt. Nun muss ich also die objekte, die gedragged wurden loswerden.

    2. Dazu benutze ich die referenzen aus dem globalem array. anhand derer kann ich die position der "alten" objekte genau ermitteln und sie anhand dessen entfernen. Sich die Positon vor dem drop zu merken macht ja keinen sinn, durch den drop kann sich ja auch die position der "alten" objekte verändert haben.

    Ich denke vom Ansatz ist das ne saubere Lösung, die auch funktioniert solange man eine echte Kopie aus dem Pasteboard bekommt. Und das ist auch immer der Fall, nur bei NSString nicht. Besonders skuril: auch bei NSString bekommt man meistens(!) eine echte Kopie zurück, nur bei bestimmten string eben nicht. Klingt komisch, ist aber so. Ich glaube das liegt daran, das die Strings, die ich benutzte teilweise schon vom system bekannt sind (bundleIdentifier).


    @Amin
    Wo sich das Objekt befindet ist ja egal, aber es ist wichtig es unterscheiden zu können. Das macht man ja ständig indem man einem Pointer auf ein Objekt richtet:

    NSObject *object1 = [[NSObject alloc] init];
    NSObject *object2 = [[NSObject alloc] init];

    => object1 != object2

    da werden ja auch Speicheradressen benutzt um die Identität eines Objektes zu bestimmen. Nur Imutable Objekte sind da wohl ne Ausnahme...

    Den String zuerst rausschmeissen und wieder reinstecken geht auch nicht, sonst würde er wären des drag & drop aus der tableview verschwinden.

    Sich den Index zu merken bringt leider auch nichts, das sich diesser durch den drop verändern kann.

    @hns
    Das würde auf jeden Fall klappen. Aber warum nötigt mich cocoa zu diesem umweg? Alle anderen objekte werden ja durch ihre speicheradressen unterschieden, nur NSString scheint da ne Ausnahme zu machen.

    Mit den MutableString funktioniert es, aber das sind dann eben mutable objekte...auch nicht ideal.

    Gruss und Danke für eure Hilfe,
    Johannes
  • Hi,

    ja klingt ertsmal nicht so schön, aber zu Drag & Drop passt es dann doch. Sonst würde man ja den Drag & Drop in derselben tableView anders behandel als zwischen 2 verschiedenen tableViews. Das geht natürlich, finde ich aber auch nicht schön da ne Unterscheidung machen zu müssen.

    Gruss,
    Johannes
  • Hi,

    ne erst nach dem drop, aber das ist ja gerade das Problem. Nach dem drop sind die Objekte doppelt im array drin, und nun muss ich die "alten" loswerden. Und um diese zu finden brauche ich die speicheradresse, und die ist eben bei den neuen objekten gleich. Deshalb entfernt er die alten und die neuen.

    Gruss,
    Johannes