NSArray sortieren - Zahlen und Sonderzeichen nach Buchstaben

  • In C# kannst Du fröhlich durch die Gegend casten, weil es eine InvalidCastException gibt, wenn das Casten nicht möglich ist.
    In C# kannst Du beispielsweise nicht einfach einen Integer in einen String casten. Das fliegt Dir mit besagter Exception um die Ohren.
    In Objective-C kannst Du einfach einen NSNumber in einen NSString casten. Ohne Probleme. Wenn Du dann aber [nsNumberInstanzAufNsStringGecasted substringInRange:myRange] versuchst, fliegt dir die App ohne sofort erkennbaren Grund um die Ohren.
    Schlimmer noch, Du liest ein 'NSNumber does not respond to selector substringInRange' und schließt vollkommen aus, dass das an Deinem Code liegen könnte, da das Casten ja geklappt hat.

    Faktisch castest Du NSNumber (void*) zu NSString (void*) und es gibt keinen Grund für diesen Cast fehlzuschlagen. ;)
    «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
  • Marco Feltmann schrieb:

    In C# kannst Du fröhlich durch die Gegend casten, weil es eine InvalidCastException gibt, wenn das Casten nicht möglich ist.
    In C# kannst Du beispielsweise nicht einfach einen Integer in einen String casten. Das fliegt Dir mit besagter Exception um die Ohren.
    In Objective-C kannst Du einfach einen NSNumber in einen NSString casten. Ohne Probleme. Wenn Du dann aber [nsNumberInstanzAufNsStringGecasted substringInRange:myRange] versuchst, fliegt dir die App ohne sofort erkennbaren Grund um die Ohren.
    Schlimmer noch, Du liest ein 'NSNumber does not respond to selector substringInRange' und schließt vollkommen aus, dass das an Deinem Code liegen könnte, da das Casten ja geklappt hat.

    Faktisch castest Du NSNumber (void*) zu NSString (void*) und es gibt keinen Grund für diesen Cast fehlzuschlagen. ;)


    nein, in obj-c castest du nicht eine NSNumber zu einem NSString sondern du castest jeweils nur pointer.
    und hier im konkreten fall hat er einen pointer auf NSString zu einem unichar (16 bit unsigned short) gecastet...
  • gritsch schrieb:

    Marco Feltmann schrieb:

    Faktisch castest Du NSNumber (void*) zu NSString (void*) und es gibt keinen Grund für diesen Cast fehlzuschlagen. ;)

    nein, in obj-c castest du nicht eine NSNumber zu einem NSString sondern du castest jeweils nur pointer.

    Steht doch da: Du castest void* zu void*.
    «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
  • Marco Feltmann schrieb:

    gritsch schrieb:

    Marco Feltmann schrieb:

    Faktisch castest Du NSNumber (void*) zu NSString (void*) und es gibt keinen Grund für diesen Cast fehlzuschlagen. ;)

    nein, in obj-c castest du nicht eine NSNumber zu einem NSString sondern du castest jeweils nur pointer.

    Steht doch da: Du castest void* zu void*.


    nein, du hast das geschrieben:

    In Objective-C kannst Du einfach einen NSNumber in einen NSString casten.
  • Gut, in dem Sinne müsste es korrekt heißen:
    'In Objective-C kannst Du problemlos einen Zeiger auf NSNumber in einen Zeiger auf NSString casten. Die damit referenzierten Objekte bleiben unverändert.'
    «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
  • Ich würde ganz gerne wieder zum Sortieren des Arrays zurückkehren, falls das für euch okay ist. :D
    In Zukunft werde ich etwas vorsichtiger beim Casten sein. Aber das Sortieren des Arrays habe ich immer noch nicht hinbekommen.

    Warum kann Apple nicht einfach eine weitere Suchoption implementieren, die Buchstaben voranstellt? Das wäre so viel einfacher. :D
  • Das ganze ist doch recht einfach: Beim Einlesen der Daten baust Du ein Array von Dictionaries auf, in denen zwei Attribute gespeichert werden: der Titel der jeweiligen Sektion und ein Unter-Array der enthaltenen Zeilen. Für alle Einträge, die nicht mit einem Buchstaben beginnen, nimmt Du "#" als Sektions-Titel. Am Ende des Einlesens schiebst Du die "#"-Sektion nach hinten. Fertig.

    Alle Datasource-Methoden können nun ganz einfach auf diese Struktur zurückgreifen, so erhältst Du die Sektions-Titel beispielsweise durch

    Quellcode

    1. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    2. {
    3. NSDictionary *sectionDict = [self.sections objectAtIndex:section];
    4. return [sectionDict objectForKey:kSTBHDDocumentSectionTitle];
    5. }

    Für den Index würde ich allerdings ein konstantes Array der Buchstaben + "#" nehmen, da sonst bei fehlenden Datensätzen diese Buchstaben nicht im Index auftauchen würden ... Das wirkt inkonsistent und wird m. E. bei Kontakten und Musik auch so gehandhabt.

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • macmoonshine schrieb:

    Wenn sie das machen würden, hättest Du wahrscheinlich nichts zu tun. +scnr+
    Wohl wahr. :D

    Danke Mattes für deine Antwort. Die Geschichte mit dem UITableView konnte ich schon lösen. Mir geht es nun vielmehr darum, wie ich jedes Array nach folgendem Schema sortieren kann: Buchstaben, Zahlen und Sonderzeichen.

    Mattik hatte schon eine recht gute Idee: Das NSArray in Unterarray aufzuteilen, diese von den Boardmitteln sortieren lassen und dann die NSArrays in gewünschter Reihenfolge zusammenfügen.

    Ich komm aber nicht drauf, wie ich alle Buchstaben in ein Array filtere, alle Zahlen und alle Sonderzeichen. Ich kann das NSArray zwar mit einem NSPredicate filtern, aber ich bekomm das halt nur hin, wenn ich beispielsweise Anfangsbuchstaben oder enthaltene Strings vergleichen muss.
  • TheFuriousLion schrieb:

    [Mir geht es nun vielmehr darum, wie ich jedes Array nach folgendem Schema sortieren kann: Buchstaben, Zahlen und Sonderzeichen.

    Ich sehe das Problem nicht: Wenn es um eine TableView wie in Contacts geht, dort wird alles außer Buchstaben in eine Sektion geschubst, "#". Also alle Datensätze mit Bordmitteln sortieren, inkl. nationaler Sonderzeichen, Groß- / Kleinschreibung etc. ... das möchte ich nicht selber coden. Dann wie beschrieben in Sektions-Dictionaries packen und gut ist. BTDT. Du denkst m. E. zu kompliziert.

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Also, ich habe das mit dem UITableView folgendermaßen gelöst:

    Ich habe zwei Properties:

    Quellcode

    1. @property (strong, nonatomic) NSDictionary *contacts;
    2. @property (strong, nonatomic, readonly) NSArray *sectionTitles;

    Hier die Getter-Methoden zu den zwei Properties:

    Quellcode

    1. - (NSDictionary *)contacts
    2. {
    3. if (!_contacts) {
    4. NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
    5. for (NSString *sectionTitle in self.sectionTitles) {
    6. [dictionary setObject:[[NSMutableArray alloc] init] forKey:sectionTitle];
    7. }
    8. _contacts = dictionary;
    9. }
    10. return _contacts;
    11. }
    12. - (NSArray *)sectionTitles
    13. {
    14. return @[@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L",@"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",@"U",@"V",@"W",@"X",@"Y",@"Z",@"#"];
    15. }
    Alles anzeigen
    Das ganze ist hier ohne Datenspeicherung. Ich füge in viewDidLoad: ein paar Datensätze hinzu.

    Und hier die zwei UITableViewDataSource Methoden:

    Quellcode

    1. - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
    2. {
    3. return self.sectionTitles;
    4. }
    5. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    6. {
    7. NSString *sectionTitle = [self.sectionTitles objectAtIndex:section];
    8. return [[self.contacts objectForKey:sectionTitle] count] ? sectionTitle : nil;
    9. }

    Funktioniert bestens und ich finde meine Version fast etwas leichter (verständlicher). Was man jetzt noch aussetzen könnte, ist, dass jedes mal ein NSArray erstellt wird, wenn sectionTitles Getter aufgerufen wird.

    Aber das Thema bezieht sich ja viel mehr auf das Sortieren von NSArrays als auf UITableViews. Bitte nicht falsch verstehen.

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

  • TheFuriousLion schrieb:

    Mattik hatte schon eine recht gute Idee: Das NSArray in Unterarray aufzuteilen, diese von den Boardmitteln sortieren lassen und dann die NSArrays in gewünschter Reihenfolge zusammenfügen.

    Ich komm aber nicht drauf, wie ich alle Buchstaben in ein Array filtere, alle Zahlen und alle Sonderzeichen. Ich kann das NSArray zwar mit einem NSPredicate filtern, aber ich bekomm das halt nur hin, wenn ich beispielsweise Anfangsbuchstaben oder enthaltene Strings vergleichen muss.
  • Liebe Leute,

    ich würde dieses Thema gerne noch einmal aufwärmen. Ich habe meine Kontakte-App nun auf CoreData aufgebaut und stehe nun wieder vor dem Problem, dass das #-Zeichen vor der A-Section kommt.

    Die sectionIndexTitles konnte ich wie folgt löschen:

    Quellcode

    1. - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
    2. {
    3. return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles];
    4. }
    Hier wird ein NSArray zurückgegeben, von A bis Z mit dem #-Zeichen am Ende. Also das funktioniert perfekt.

    Wenn es aber darum geht, den sections einen title zu vergeben, stehe ich wieder vor dem Problem, dass die #-Section vor der A-Section kommt. Wenn man auf die Buchstaben der sectionIndexTitles tippt, springt man auch zur richtigen Section, nur stimmt die Reihenfolge nicht, was mich sehr stört. Hier die Methoden:

    Quellcode

    1. - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
    2. {
    3. return [[self.fetchedResultsController sectionIndexTitles] indexOfObject:title];
    4. }
    5. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    6. {
    7. id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    8. return [sectionInfo name];
    9. }

    Ich hoffe wirklich, dass ihr mir helfen könnt.

    TheFuriousLion
  • So ganz spontan könntest Du versuchen Deine Ergebnisse des FetchedResultControllers in einer Subklasse umzubiegen.

    Alternativ modifizierst Du den Index entsprechend…

    Quellcode

    1. - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
    2. {
    3. NSInteger result = [[self.fetchedResultsController sectionIndexTitles] indexOfObject:title];
    4. if(result == 0) {
    5. result = [[self fetchedResultsController sectionIndexTitles] count] - 1;
    6. }
    7. else {
    8. result--;
    9. }
    10. return result;
    11. }
    12. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    13. {
    14. if(section == 0) {
    15. section = [[self.fetchedResultsController sections] count] -1;
    16. }
    17. else {
    18. section--;
    19. }
    20. id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    21. return [sectionInfo name];
    22. }
    Alles anzeigen


    Allerdings sortiert jede Apple-eigene Kontakte-App beginnend bei # und endend bei Z.
    Warum um alles in der Welt möchtest Du von dieser Vorgabe abweichen?
    «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
  • Vielen Dank für deinen Code, Marco. Leider funktioniert er nicht. Die Reihenfolge der section headers wird zwar geändert - jedoch nicht wie gewünscht - aber die rows für die einzelnen Sections bleiben an ihrer alten Position. Also ist jetzt beispielsweise die Nummer 0000 000000 in der A-Section.

    Marco Feltmann schrieb:

    Allerdings sortiert jede Apple-eigene Kontakte-App beginnend bei # und endend bei Z.
    Warum um alles in der Welt möchtest Du von dieser Vorgabe abweichen?
    Leider nein, die Kontakte-App, die Telefon-App und die Musik-App sortieren alle von A bis Z und hängen das # an. Deshalb versuche ich ja so krampfhaft das nachzubauen. Es will mir aber nicht gegönnt sein. :D
  • Du musst natürlich alles anpassen, was irgendwie auf den Section Index hinweist.

    Dir ist übrigens bekannt, dass es sich bei [fetchedResultsController sections] und [fetchedResultsController sectionIndexTitles] nicht um Hexenwerk sondern um ganz normale Arrays handelt, die Du entsprechend sortieren kannst?
    «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
  • Dass es hierbei um NSArrays handelt war mir klar, aber nicht, dass ich diese sortieren kann. Ich müsste beispielsweise die sections mit dem sortierten NSArray überschreiben. Gibt es hier keine Probleme mit Core Data?

    Aber das Sortieren bringt mir im Moment leider auch noch nichts, da ich noch nicht herausgefunden habe, wie ich dieses verdammte #-Zeichen hinter's Z bekomm. ^^
  • TheFuriousLion schrieb:

    Gibt es hier keine Probleme mit Core Data?

    Welche Art von Problemen erwartest Du?
    Du nutzt ein Objekt aus dem FetchedResultsController für Dein neues Objekt.
    Da hat Core Data überhaupt keine Aktien drin.

    (Arg, die Sortierung von iOS und Mac OS verwechselt…)
    «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

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Marco Feltmann ()