Zu doof um NSFastEnumeration zu benutzen. ^^

  • Zu doof um NSFastEnumeration zu benutzen. ^^

    Moin,

    ich habe da gerade so ein kleines Verständnisproblem mit dem NSFastEnumeration Protokoll, genauer gesagt mit
    - (NSUInteger)countByEnumeratingWithState: (NSFastEnumerationState *)state objects: (id *)stackbuf count: (NSUInteger)len

    Vielleicht zum Setup: ich benutze ein NSMapTable, da ich so dictionarymäßig Zuordnungen von Objekten verwalten möchte.
    Da keine der Objekte NSCopying implementieren (aus Gründen) bin ich beim NSMapTable hängen geblieben.

    Vielleicht ist die Collection sogar schon suboptimal. Sie unterstützt leider nur objectForKey:, ich würde mich aber auch über eine Art keyForObject: freuen. ;)

    Wie dem auch sei, ich möchte alle Objekte dieser NSMapTable haben.
    Im Gegensatz zu anderen Collections gibt es leider kein -allObjects.

    Nun könnte ich objectEnumerator verwenden. Laut Doku sei NSFastEnumeration schneller.
    Wenn mein Wissen mich nicht trügt, nutzt

    C-Quellcode

    1. for(id object in collection) {}

    eben jenes NSFastEnumeration Protokoll.

    Das wirft mir allerdings nur die Keys aus, nicht die Values.

    Jetzt frage ich mich, wie ich über das NSFastEnumeration Protokoll die einzelnen Values meines NSMapTables bekommen kann...

    Das ist eine rein interessierte Frage, da ich das Ursprungsproblem schon (in nur bedingt sauber und performant, aber POITROAE) via objectEnumrator gelöst habe.

    C-Quellcode

    1. [[_managedPoints objectEnumerator] allObjects];
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Apfelbeisser schrieb:

    Hm? Eben in einer for Schleife mit objectForKey alle Objekte abholen? Versteh ich was falsch?

    Ja, so habe ich das zunächst auch interpretiert.

    Nur verstehe ich dann den Zusatz in der Doku zu -keyEnumerator nicht:
    Discussion
    The following code fragment illustrates how you might use the method.

    C-Quellcode

    1. NSEnumerator *enumerator = [myMapTable keyEnumerator];
    2. id value;
    3. while ((value = [enumerator nextObject])) {
    4. /* code that acts on the map table's keys */
    5. }

    Special Considerations
    It is more efficient to use the fast enumeration protocol (see NSFastEnumeration).


    Gut, beim keyEnumerator mag halt for(id key in mapTable){} effizienter sein.

    Doch stehen diese Special Considerations halt auch bei -objectEnumerator.
    Daher meine Frage: wie kann ich das NSFastEnumeration Protokoll nutzen, um gezielt die Werte durchzuenumerieren, anstatt über die Keys zu gehen?

    Vermutung: gar nicht, ich muss über die Keys gehen, weil das forin-Konstrukt die einzige Zugriffsmöglichkeit auf das NSFastEnumeration Protokoll bietet.

    Jetzt warte ich eigentlich nur auf eine Bestätigung oder Widerlegung dieser Vermutung. ^^
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Mit (vereinfacht implementiert)

    Quellcode

    1. NSFastEnumerationState state = {0};
    2. id objects[10];
    3. NSUInteger count;
    4. while ((count = [yourMapTable countByEnumeratingWithState:&state objects:objects count:10]) > 0) {
    5. NSLog(@"count: %lu", count);
    6. NSLog(@"Key: %@", state.itemsPtr[0]);
    7. NSLog(@"Value: %@", state.itemsPtr[1]);
    8. }


    kommst du schon auf interne Daten von der for-Schleife.

    Ich weiss nicht, wie NSMapTable genau die Daten an countByEnumeratingWithState liefert,
    aber auf die Daten kommst du schon.

    Ob du damit schneller wirst, kann ich nicht wirklich pauschal beantworten.

    Eventuell kannst du es benchmarken?

    Ausführliches:
    mikeash.com/pyblog/friday-qa-2…ing-fast-enumeration.html
    Aus macfreakz wurde Apfelbeisser …
  • Apfelbeisser schrieb:

    Quellcode

    1. NSLog(@"Key: %@", state.itemsPtr[0]);
    2. NSLog(@"Value: %@", state.itemsPtr[1]);

    Ah, danke. Da hakte mein Verständnis. :)
    itemsPtr kann also nicht nur ein eindimensionales Array mit den Key Objekten sein, sondern auch ein zweidimensionales Array mit allen Objekten.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Chartus: Tue ich. Doch die Doku meinte, das fast enumeration Protokoll sei effizienter. Deshalb die neugierige Frage.

    Apfelbeisser: Ja, ich meinte was Anderes.
    Ich meinte: itemsPtr kann also nicht nur ein Zeiger auf ein einzelnes Objekt, sondern auch auf ein Array mit allen Objekten sein.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • chartus schrieb:

    das for( id in ... ) benutzt doch das fastenumeration protokoll?!

    Deshalb ja meine Verwirrung.

    Wobei folgende Codeschnippsel dasselbe Resultat liefern:

    C-Quellcode

    1. for (id key in [myMapTable keyEnumerator]) {
    2. ...
    3. }

    C-Quellcode

    1. for (id key in myMapTable) {
    2. ...
    3. }


    Nur steht in der Doku halt explizit: dem keyEnumerator sei das NSFastEnumeration Protokoll vorzuziehen, da dieses performanter sei.

    Erster Code wendet ja fastEnumeration auf den NSEnumerator an während zweiter Code fastEnumeration direkt auf dem NSMapTable ausführt.
    Ich verstehe die Doku so, dass das Erstellen eines Enumerators (gleich welchen Enumerators, also egal ob keyEnumerator oder objectEnumerator) weniger performant sei als das Ausführen der -countByEnumeratingWithState:objects:count:

    Deshalb suchte ich einen Weg, darüber an die Objekte zu kommen.
    for(id key in myMapTable) ist also offenbar nur ein bequemerer Weg für den nahezu direkten Zugriff auf state.itemsPtr[0].

    Danke für das Zitat aus der Doku, gritsch.
    Dem Struct NSFastEnumerationState habe ich offenbar keinerlei Aufmerksamkeit geschenkt.
    Deshalb war ich wohl auch so verwirrt, wieso die Methode keinerlei sinnvolle Objekte zurückgibt.

    Ich glaube, ich werde zu Übungszwecken mal ein paar NSFastEnumeration Protocols implementieren.
    Learning by doing und zumindest im Grundansatz habe ich es nun kapiert. =)
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • chartus
    Wie geschrieben: die Lösung läuft via [[myMapTable objectEnumerator] allObjects];
    Es ging mir um das 'unter der Motorhaube'.

    gritsch
    Dann geht mir ja die Zuordnung Objekt 1 (non-NSCopying) zu Objekt 2 (non-NSCopying) flöten.
    Ein großer Freund von Datenredundanz bin ich irgendwie auch nicht. Ich meine, ich habe die Pointer doch einmal zugriffsbereit. Wieso dann noch mal in eine andere Collection stopfen?
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Lucas de Vil schrieb:

    chartus
    gritsch
    Dann geht mir ja die Zuordnung Objekt 1 (non-NSCopying) zu Objekt 2 (non-NSCopying) flöten.
    Ein großer Freund von Datenredundanz bin ich irgendwie auch nicht. Ich meine, ich habe die Pointer doch einmal zugriffsbereit. Wieso dann noch mal in eine andere Collection stopfen?


    ist klar, deswegen ja zusätzlich das set.
    manchmal muss man zu gunsten der geschwindigkeit etwas speicher verschwenden ;)
  • gritsch schrieb:

    manchmal muss man zu gunsten der geschwindigkeit etwas speicher verschwenden ;)

    Stimmt.
    Wenn also der aktuelle Ansatz wirklich einmal sehr langsam werden sollte und ich mit dem Direktzugriff auf das NSFastEnumeration Protokoll nix werde, dann fang ich vielleicht an, mit weiteren Pointern meinen Speicher zu belegen.
    Zum Glück kosten Zeiger recht wenig. ^^
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P