Czytałem, że najlepszym sposobem tworzenia indeksu (a-z z boku uitableview) jest ustawienie tablicy nsdictionaries, gdzie każdy słownik odpowiada sekcji, a klucz rowValue zawiera tablicę wierszy.

NSDictionary
    headerTitle => ‘A’
    rowValues => {”Aardvark”, “Ape”, “Aquaman”}
NSDictionary
    headerTitle => ‘B’
    rowValues => {”Bat”, “Boot”, “Bubbles”} etc

Ale jak można to utworzyć z tablicy wszystkich tytułów wierszy - {”Aardvark”, „Ape”, „Aquaman”, „Nietoperz”, „Boot”, „Bąbelki”, „Kot”, „Kapusta” itp.} . ..?

10
cannyboy 23 sierpień 2011, 13:23

3 odpowiedzi

Najlepsza odpowiedź
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad
{
    [super viewDidLoad];
    NSMutableArray *temp = [[NSMutableArray alloc] init];
    NSMutableArray *temp2 = [[NSMutableArray alloc] init];
    for(int i = 0; i < tableListArray.count; i++)
    {
        NSString *string = [tableListArray objectAtIndex:i];
        NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
        [dict setObject:string forKey:@"Name"];
        [dict setObject:[NSNumber numberWithInt:i] forKey:@"ID"];
        NSString *firstString = [string substringToIndex:1];
        if([temp2 containsObject:firstString] == NO || temp2.count == 0)
        {
            if(temp2.count != 0)
            {
                [temp addObject:temp2];
                [temp2 release];
                temp2 = [[NSMutableArray alloc] init];
            }
            [temp2 addObject:firstString];
        }
        [temp2 addObject:dict];
        [dict release];
    }
    [temp addObject:temp2];
    detailListArray = [[NSArray alloc] initWithArray:temp];
    [temp release];
    [temp2 release];
}

#pragma mark -
#pragma mark Table view data source
- (NSInteger)tableView:(UITableView *)tableView 
sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    int i = 0;
    for(NSArray *array in detailListArray)
    {
        NSString *string = [array objectAtIndex:0];
        if([string compare:title] == NSOrderedSame)
            break;
        i++;
    }
    return i;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return detailListArray.count;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSArray *array = [detailListArray objectAtIndex:section];
    return [array objectAtIndex:0];
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView 
{
    NSMutableArray *titleArray = [NSMutableArray array];
    [titleArray addObject:@"A"];
    [titleArray addObject:@"B"];
    [titleArray addObject:@"C"];
    [titleArray addObject:@"D"];
    [titleArray addObject:@"E"];
    [titleArray addObject:@"F"];
    [titleArray addObject:@"G"];
    [titleArray addObject:@"H"];
    [titleArray addObject:@"I"];
    [titleArray addObject:@"J"];
    [titleArray addObject:@"K"];
    [titleArray addObject:@"L"];
    [titleArray addObject:@"M"];
    [titleArray addObject:@"N"];
    [titleArray addObject:@"O"];
    [titleArray addObject:@"P"];
    [titleArray addObject:@"Q"];
    [titleArray addObject:@"R"];
    [titleArray addObject:@"S"];
    [titleArray addObject:@"T"];
    [titleArray addObject:@"U"];
    [titleArray addObject:@"V"];
    [titleArray addObject:@"W"];
    [titleArray addObject:@"X"];
    [titleArray addObject:@"Y"];
    [titleArray addObject:@"Z"];
    return titleArray;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSArray *array = [detailListArray objectAtIndex:section];
    return (array.count - 1);
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                                    reuseIdentifier:@"CELL"] autorelease];
    NSArray *array = [detailListArray objectAtIndex:indexPath.section];
    NSDictionary *dict = [array objectAtIndex:indexPath.row + 1];
    cell.textLabel.text = [dict objectForKey:@"Name"];
    return cell;
}

#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSArray *array = [detailListArray objectAtIndex:indexPath.section];
    NSDictionary *dict = [array objectAtIndex:indexPath.row + 1];
    int entryID = [[dict objectForKey:@"ID"] intValue];
     // Do what ever you want to do with the selected row here....
}

To jest kod, którego użyłem w jednym z ostatnich projektów.

5
Robin 23 sierpień 2011, 13:30

Niedawno miałem podobny cel i tak go rozwiązałem. Zaletą tego rozwiązania nad Robinem jest to, że tworzy tablicę tytułów indeksów dynamicznie w oparciu o zawartość Twojej tablicy i nie będzie zawierała indeksów dla pustych sekcji (plus jest trochę bardziej przejrzysta).

Utworzyłem kategorię NSMutableDictionary, która przyjmuje tablicę danych jako parametr i zwraca NSMutableDictionary (nazwiemy ją indexDictionary i powinna to być zmienna instancji):

// if your data is static, you can call this in `viewDidLoad`
indexDictionary = [NSMutableDictionary createDictionaryForSectionIndex:arrayOfStrings];

Metoda kategorii:

@implementation NSMutableDictionary (DictionaryForSectionIndex)

+(NSMutableDictionary *)createDictionaryForSectionIndex:(NSArray *)array
{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    for (char firstChar = 'a'; firstChar <= 'z'; firstChar++)
    {
        //NSPredicates are fast
        NSString *firstCharacter = [NSString stringWithFormat:@"%c", firstChar];
        NSArray *content = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF beginswith[cd] %@", firstCharacter]];
        NSMutableArray *mutableContent = [NSMutableArray arrayWithArray:content];

        if ([mutableContent count] > 0)
        {
            NSString *key = [firstCharacter uppercaseString];
            [dict setObject:mutableContent forKey:key];
            NSLog(@"%@: %u", key, [mutableContent count]);
        }
    }

    return dict;
}

@end

/*

**Input:** 
{"Aardvark", "Cabbage", "Boot", "Eggs", "Ape", "Aquaman", "Elephant", "Cat", "Bat", "Bubbles"}

**Output:**
NSMutableDictionary
    key => 'A'
    object => {"Aardvark", "Ape", "Aquaman"}

    key => 'B'
    object => {"Bat", "Boot", "Bubbles"}

    key => 'C'
    object => {"Cat", "Cabbage"}

    key => 'E'
    object => {"Elephant", "Eggs"}

*/

Następnie tworzę zmienną instancji NSArray, aby sortować i przechowywać wszystkie klucze z indexDictionary:

// this line should follow the creation of `indexDictionary`

sortedKeys = [[indexDictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

// Output, in this case, is {'A', 'B', 'C', 'E'}

Masz teraz wszystko, czego potrzebujesz, aby skonfigurować indeks dla swojej tabeli. Zastosuj następujące metody (jeśli coś nie jest oczywiste, po prostu daj mi znać):

//this code assumes `sortedKeys` is not empty

#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return ([sortedKeys count]);
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSString *key = [sortedKeys objectAtIndex:section];
    return [[indexDictionary valueForKey:key] count];
}


-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return ([sortedKeys objectAtIndex:section]);
}


-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    return sortedKeys;
}


-(NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    return index;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // preceding code...

    NSString *key = [sortedKeys objectAtIndex:indexPath.section];
    NSArray *array = [indexDictionary objectForKey:key];
    NSString *yourString = [array objectAtIndex:indexPath.row];

    cell.textLabel.text = yourString;

    // following code...
}

Wynikiem jest tabela z indeksem, który pomija litery, które nie mają powiązanych danych.

16
lobianco 8 listopad 2012, 02:38
2
To naprawdę fantastyczna odpowiedź. Dziękuję.
 – 
daspianist
30 styczeń 2014, 20:39
Jeśli masz tablicę słowników, a nie tablicę ciągów, jedyną rzeczą, którą musisz zrobić inaczej, jest zaktualizowanie ciągu predykatu tak, aby był podobny do name beginswith[cd] %@ zamiast SELF beginswith[cd] %@. Spowoduje to posortowanie tablicy słowników według pola nazwy każdego słownika.
 – 
John Erck
1 luty 2014, 04:17

Pracowałem nad jednym projektem, w którym potrzebuję dynamicznych rozwiązań dla tego samego problemu, więc wymyśliłem to rozwiązanie, które zwraca słownik z tylko dostępnymi sekcjami. Mam nadzieję, że komuś pomoże.

-(NSMutableDictionary *)getSortedDataWithArray:(NSArray *)dataArray{
  NSMutableDictionary *allDataDictionary = [[NSMutableDictionary alloc]init];

  for(int i = 0 ; i< dataArray.count ;i++){

    NSString *currentStr = [[[dataArray objectAtIndex:i] substringToIndex:1] uppercaseString];
    NSArray *allKeysArray = allDataDictionary.allKeys;

    if([allKeysArray containsObject:currentStr]){
        NSMutableArray *currentArray = [[NSMutableArray alloc] initWithArray:[allDataDictionary valueForKey:currentStr]];
        [currentArray addObject:[dataArray objectAtIndex:i]];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@" ,currentStr];
        NSArray *finalArray = [currentArray filteredArrayUsingPredicate:predicate];
        [allDataDictionary setValue:finalArray forKey:currentStr];
    }
    else{
        NSMutableArray *finalArray = [[NSMutableArray alloc] initWithObjects:[dataArray objectAtIndex:i], nil];

        [allDataDictionary setValue:finalArray forKey:currentStr];
    }
  }
 return allDataDictionary;
}
0
kk78626 26 marzec 2018, 16:35