Enumeration erweitern

  • Enumeration erweitern

    Hallo zusammen,

    gibt es eine Möglichkeit Enumerations zu erweitern?

    Ich hab ne Klasse die mit unsigned int Werten arbeitet. Dabei gibt es ein paar standard Werte, z.B. locationNone = 0; locationScreen =1;... die die Klasse mitbringen muss. Für die Wiederverwertbarkeit sollen diese Standardwerte dann mit individuellen Werten der App erweitert werden (z.B. locationWorkspace = x;....).

    Irgendeine Idee wie man sowas realisieren kann?


    Gruß Manfred
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • RE: Enumeration erweitern

    Ich ehme an, dass du willst, dass automatisch die custom Konstanten nach oben verschoben werden, wenn sich die allgemeinen erweitern? Dann ist mir nichts bekannt. Letztlich wäre es ja eine Ableitung.

    Für solche Fälle kann man Nummernkreise bilden, damit sich beide Zählungen nicht n die Quere kommen. Also: Allgemein von 0-999, speziell von 1000-1999.

    Aber bedenke eines: Ein Identiifier von NSString ist eine Konstante und liegt daher nur einmal im Spicher. BeiÜbergaben wird stets nur der Pointer genommen. Der hat die gleiche Größe wie ein Int. Und die Vergleichsoperation wird ohnehin wohl zunächst auf Identität geprüft, was den gleichen Laufzeit-Aufwand wie ein Integer-Vergleich verursacht. D kannst es dann auch häufig selbst machen:

    Quellcode

    1. yourEnum type = …
    2. if( type == mySpecialType )
    3. // verhält sich so wie
    4. NSString* const myIdentifier = @"SomeThing";
    5. if( type == myidentifier )
    Was spricht also gegen String-Identifier?
    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"?
  • Was spricht also gegen String-Identifier?


    Die Routinen werden oft durchlaufen.

    Also konkret habe ich mir einen "Drag and Drop Handler" gebaut. Meine App arbeitet intern viel mit D&D. Anstatt in jeder View die Stings von Pasteboard und Co. auszuwerten, habe ich eine Shared Instance bei der Source, Destination und Dragtype gesetzt werden (alles unsigned int). Die siebe ich durch und bekomme eine action.

    Vorteil (zumindest meiner Meinung nach):

    1. geht schneller als jedesmal Strings zu vergleichen.
    2. die Auswertung einer D&D Operation findet nicht verteilt auf x Views statt, sondern im Delegate meines "DragCenters"

    Um es kurz zu machen: Ich halte Stringvergleiche in Methoden wie

    Quellcode

    1. - (void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint

    für ne ziemliche Resourcenverschwendung, zwei int zu vergleichen ist da wesentlich sparsamer
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • Original von kressevadder

    Quellcode

    1. - (void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint

    für ne ziemliche Resourcenverschwendung, zwei int zu vergleichen ist da wesentlich sparsamer
    Genau um die zu vermeiden hat jedes NSObject die Methode -hash

    Algorithmus für Vergleiche (-isEqual:)

    1. wenn Adresse (Pointer) gleich -> gleich
    2. wenn Hash verschieden -> verschieden
    3. dann erst Zeichen für Zeichen vergleichen

    D.h. in 99,9% der Fälle dauert ein [str isEqualToString:abc] mit const NSString *abc=@"abc"; nur 2-3 mal so lange wie ein int-Vergleich. Bei 2GHz-CPU fällt das nicht auf. Der Benutzer und die Harddisks sind nicht proportional zur Taktfrequenz schneller geworden.

    -- hns
  • Original von kressevadder
    Ach herje,

    da tun sich ja Bildungslücken auf. Ich dachte jedesmal, wenn ich irgendeinen String den ich definiert habe benutze, wird ein neuer String angelegt. Aber das ist immer der Selbe. Klar brauch ich dann keinen Stringvergleich zu machen, sondern einfach nur die Pointer vergleichen.

    Autsch....


    dann erstellst du den mal dynamisch oder lädst ihn aus einem loc-file oder holst den identifier aus irgendeinem GUI-Element und schon ist meinString == andererString ein problem... also trotzdem isEqualToString verwenden!
  • dann erstellst du den mal dynamisch oder lädst ihn aus einem loc-file oder holst den identifier aus irgendeinem GUI-Element und schon ist meinString == andererString ein problem... also trotzdem isEqualToString verwenden!

    Das ist klar,

    aber wenn ich "sicherstelle" das mit der Klasse nur definierte Konstanten verwendet werden dürfen, sollte das doch gehen. Ich will mit der Klasse ja nichts speichern, sondern meine Filterlogik für mein Drag & Drop implementieren, da sollte das eignetlich gehen. Wäre halt die Möglichkeit die Konstanten zu erweitern.

    Also in solchen Methoden, die massig durchlaufen werden, tut es mir einfach weh, isEqualToString: zu verwenden.

    EDIT: Also 2-3x soviel für einen String Vergleich wie für einen int Vergleich fine ich ein Wort. Nur weil ich 2GHz unterm Popo habe, will ich noch nicht ne halbe Kilowattstunde bei einem Drag & Drop oder irgendeinem Event verbraten. Software sollte ja auch Klimafreundlich sein ;)

    Zumal die 2-3 mal wohl wirklich der Idealfall sind @"kWLMyApplicationDragItemWorkspaceNetworkuserWithNoPrivilegesAndIQBelowTen" dürfte da schon etwas mehr in anspruch nehmen.
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • Original von gritsch
    Original von kressevadder
    Zumal die 2-3 mal wohl wirklich der Idealfall sind @"kWLMyApplicationDragItemWorkspaceNetworkuserWithNoPrivilegesAndIQBelowTen" dürfte da schon etwas mehr in anspruch nehmen.


    nein, warum auch?
    Doch, doch, wenns so läuft wie hns es beschrieben hat (und das ist schon ziemlich sicher).

    Z.B. hat man den String string1 = @"aaa" und den String string2 @"aab" und dann passiert ja folgendes:
    * string1 != string2 --> alles, klar weiter im Text
    * [stirng1 length] == [string2 length] --> gleich lang, könnten also gleich sein
    * 1. Buchstabe von string1 == 1. Buchstabe von string2
    * 2. Buchstabe von string1 == 3. Buchstabe von string2
    * 3. Buchstabe von string1 != 3. Buchstabe von string2 --> Strings sind ungleich.

    Wie genau das mit dem Hash läuft, weiß ich grad net…
    "Wales is the land of my fathers. And my fathers can have it." - Dylan Thomas
  • Mh, in GNUStep siehts so aus:

    Quellcode

    1. - (BOOL) isEqualToString: (NSString*)aString
    2. {
    3. if ([self hash] != [aString hash])
    4. return NO;
    5. if (strCompNsNs(self, aString, 0, (NSRange){0, [self length]})
    6. == NSOrderedSame)
    7. return YES;
    8. return NO;
    9. }


    Der Hash wird bei jedem Aufruf der -hash Methode neu berechnet.
    Das wäre dann etwas ungünstig, ja…
    "Wales is the land of my fathers. And my fathers can have it." - Dylan Thomas
  • Demnach wäre es aber der denkbar ungünstigste Fall, wenn zwei verschiedene Strings jeweils die Länge 12345 und sich im letzten Zeichen unterscheiden ;) , dagegen ist der Vergleich zweier int immer das Gleiche.

    Aber was anderes, selbst wenn es nur 2-3x ist - 2-3x ist viel, bei Methoden die 1 Mio mal aufgerufen werden.
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • Oder du vergleichst die Strings mit "==", kommt eben aufs gleiche raus.
    Ich weiß auch nicht so ganz, ob ich das Ausgangsproblem verstanden hab, ich glaub, ich würd halt direkt alles in eine enum schmeißen.
    "Wales is the land of my fathers. And my fathers can have it." - Dylan Thomas
  • ich würd halt direkt alles in eine enum schmeißen.


    Exakt!

    Das Problem war, daß meine Klasse bestimmte Standardwerte hat. Wenn ich die Klasse in einer anderen App verwende möchte ich auch neue Werte hinzufügen, also müste das erweiterbar sein.

    Eigentlich ist aber auch das wurscht, denn solange ich das nur für mich benutzte kann ich mich auch dran halten das blaBlubNone = 0 ist.

    Ich hab das jetzt mit den Strings gemacht, und vergleiche die Pointer. So hab ich die Erweiterbarkeit die ich brauche. Und Himmel, Arsch und Zwirn, ich darf halt nur Keys verwenden die ich mit #define festlege. Diese Konvention kann ich gerade noch mit mir eingehen.
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • Original von læng
    Mh, in GNUStep siehts so aus:

    Quellcode

    1. - (BOOL) isEqualToString: (NSString*)aString
    2. {
    3. if ([self hash] != [aString hash])
    4. return NO;
    5. if (strCompNsNs(self, aString, 0, (NSRange){0, [self length]})
    6. == NSOrderedSame)
    7. return YES;
    8. return NO;
    9. }


    Der Hash wird bei jedem Aufruf der -hash Methode neu berechnet.
    Das wäre dann etwas ungünstig, ja…



    so ne scheiße - warum ist da kein if (self == aString) return YES; drin?
  • Original von kressevadder
    Ich hab das jetzt mit den Strings gemacht, und vergleiche die Pointer. So hab ich die Erweiterbarkeit die ich brauche. Und Himmel, Arsch und Zwirn, ich darf halt nur Keys verwenden die ich mit #define festlege. Diese Konvention kann ich gerade noch mit mir eingehen.


    du wirst dir dafür vielleicht noch mal in den arsch beißen.
    denn normalerweise schreibt man solchen code ja nicht nur um ihn ein einzgies mal zu verwenden sondern auch in anderen programmen. Dort trifft das dann nimmer zu und bis du rausfindest (weil erinnern kannst dich sicher nimmer dran) dass du blöderweise strings mit == vergleichst ist viel wasser den bach runter geflossen.
    Also mach es entweder richtig oder greif auf ints aus enums zurück. Verwende da einfach verschiedene bereiche wie tom schon sagte.
    Andere möglichkeit wäre auch 'ASDF' ;)
  • Vielleicht wirds so klarer:
    #import <Cocoa/Cocoa.h>


    // defined items
    #define kWLDragItemNone @"WLDragItemNone"
    #define kWLDragItemScreen @"WLDragItemScreen"

    // defined types
    #define kWLDragDatatypeNone @"kWLDragDatatypeNone"

    // defined operations
    #define kWLDragOperationNone @"WLDragOperationNone"





    @interface WLDraggingCenter : NSObject {
    id _delegate;

    NSString *_sourceItem;
    NSString *_destinationItem;
    NSString *_dragDataType;
    NSString *_dragOperation;

    id _dragDataObject;
    }

    +(id)defaultCenter;

    -(id)delegate;
    -(void)setDelegate:(id)object;


    -(void)finishCurrentDragOperation;

    @end

    @interface WLDraggingCenter (SourcesAndCo)

    -(NSString *) dragSourceItem;
    -(void) setDragSourceItem:(NSString *)item;

    -(NSString *) dragDestinationItem;
    -(void) setDragDestinationItem:(NSString *)item;

    -(NSString *) dragDataType;
    -(void) setDragDataType:(NSString *)type;

    -(id)dragDataObject;
    -(void)setDragDataObject:(id)object;

    -(NSString *) dragOperation;

    @end

    @interface WLDraggingCenter (Delegates)

    -(NSString *) dragOperationForDragSource: (NSString *)source dragDestination: (NSString *)destination dragDataType: (NSString *)type;
    -(NSCursor *) cursorForDragOperation: (NSString *)operation;

    @end

    Ich hol mir das über ne shared instance.

    geht ein Drag los, setzte ich source, type und object. Mein drag destination wird dann jeweils gesetzt, was dann die Delegates aufruft und entsprechend dragOpration (Nicht verwechseln mit NSDragOperation), aufruft. Wird der Drag beendet, hole ich mir nur opration und das Objekt ab.

    Warum das Ganze?

    Ich hab z.B. ne TableView, die ganz verschiedene Dinge Anzeigt - Trash, Kategorien, Wokspace.

    Habe ich jetzt in meiner Sidebar z.B. Trash gewählt und der Drag geht los, setzt die TableView den DragSource auf kWLDragItemTrash. Dragge ich auf den Mülleimer in der Sidebar, setzt das destination auf kWLDragItemTrash. In meinem Delegate dann If (source == destination) return kNoAction;

    Dadurch erspare ich mir, jedesmal im Pasteboard rumzuwühlen, zu schauen, was meine TableView gerade für eine Funktion hat usw.
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • dann erstellst du den mal dynamisch oder lädst ihn aus einem loc-file oder holst den identifier aus irgendeinem GUI-Element
    Also, wenn das als globale Konstante definert ist, sollte man es auch als globale Konstante verwenden. In eine Datei schreiben ist da eher ungünstig, bei Enums wie bei Strings.

    an kann so etwas als zusätzliches Schmankerl machen. Aber das ist dein fairer Vergleich mehr. Denn auch ein Tag mit einer Konstanten aus einem Header ist gefährlich.
    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"?
  • Demnach wäre es aber der denkbar ungünstigste Fall, wenn zwei verschiedene Strings jeweils die Länge 12345 und sich im letzten Zeichen unterscheiden
    Nein, das wär nicht denkbar ungünstig, da dann gewiss der Hash verschieden ist. ;) Denkbar schlecht ist es, wenn beide Strings gleich sind, aber dennoch eine unterschiedliche Adresse haben.

    Außerdem sollte man keine Mutables verwenden, da die naturgemäß keinen anständigen Hash haben. Hierzu gibt es einen älteren Thread von mir.
    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"?