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.} . ..?
3 odpowiedzi
#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.
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.
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;
}
Podobne pytania
Nowe pytania
objective-c
Tego znacznika należy używać tylko w przypadku pytań dotyczących funkcji Objective-C lub zależnych od kodu w języku. Tagi [cocoa] i [cocoa-touch] powinny być używane, aby zapytać o ramy lub klasy Apple. Użyj powiązanych tagów [ios], [macos], [apple-watch] i [tvos] w przypadku problemów specyficznych dla tych platform.
name beginswith[cd] %@
zamiastSELF beginswith[cd] %@
. Spowoduje to posortowanie tablicy słowników według pola nazwy każdego słownika.