ПРОГРАММИРОВАНИЕ ПОД IPHONE, IPAD OBJECTIVE-C часть 2

Индексированная таблица

 

Индексированная таблица это еще один способ представления данных в iOS. С ней вы могли сталкиваться в стандартном приложении «Контакты». В этом уроке я покажу как создавать таблицы такого вида в своих приложениях. Для начала создадим новый проект на основе шаблона Single View Application и назовем его IndexedTable. На картинке в начале урока видна таблица заполнена именами. Я предлагаю не вносить список всех имен в код проекта, а хранить их в отдельном текстовом файле. Скачайте этот файл по ссылке и добавьте его в проект.

 

Прежде чем этот список попадет в таблицу — его нужно прочитать с файла и превратить в массив. Для этого изменим методе viewDidLoad:

 

<code data-result="[object Object]">- (void)viewDidLoad
{
    [super viewDidLoad];   

    NSString *path = [[NSBundle mainBundle] pathForResource:@"names" ofType:@"txt"];
    NSString *textNames = [NSString stringWithContentsOfFile:path 
                                                    encoding:NSUTF8StringEncoding 
                                                       error:nil];
    NSArray *notValidNames = [textNames componentsSeparatedByString:@"п"];
    NSLog(@"%@", notValidNames);
}</code>

 

Этот метод выполняет чтение файла, формирование массива имен и вывод этот массива в консоль. Но полоса индексов в правой части таблици умеет работать только с секциями. То есть, каждый элемент индекса соответствет не ячейке таблицы, а секции. А значит, что все наши имена нужно разбить по секциям. Но это не единственный ньюанс работы с индексированной таблицей. До этого мы привыкли, что у таблици есть один источник данных (один массив или словарь, с которого заполняются поля ячеек). Теперь нам понадобиться два источника — первый, как обычно, для ячеек и второй — для списка индексов. Поэтому нам прийдется определить два источника данных и корректно их заполнить. Ниже вы можете посмотреть как это сделал я:

 

ViewController.h

<code data-result="[object Object]">#import &lt;UIKit/UIKit.h&gt;

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet UITableView *namesList;
@property (strong, nonatomic) NSMutableDictionary *names;
@property (strong, nonatomic) NSMutableArray *sectionKeys;

@end</code>

 

ViewController.m

<code data-result="[object Object]">#import "ViewController.h"

@implementation ViewController

@synthesize namesList;
@synthesize names;
@synthesize sectionKeys;

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.namesList = nil;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.names = [NSMutableDictionary dictionary];
    self.sectionKeys = [NSMutableArray array];    

    NSString *path = [[NSBundle mainBundle] pathForResource:@"names" ofType:@"txt"];
    NSString *textNames = [NSString stringWithContentsOfFile:path 
                                                    encoding:NSUTF8StringEncoding 
                                                       error:nil];
    NSArray *notValidNames = [textNames componentsSeparatedByString:@""];

    for (NSString *name in notValidNames) {
        NSString *sectionName = [name substringToIndex:1];
        NSMutableArray *namesInSection = nil;

        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF == %@", sectionName];
        NSArray *foundSection = [sectionKeys filteredArrayUsingPredicate:predicate];
        if (foundSection.count) {
            namesInSection = [names objectForKey:sectionName];
        } else {
            namesInSection = [NSMutableArray array];
            [sectionKeys addObject:sectionName];
        }

        [namesInSection addObject:name];
        [names setObject:namesInSection forKey:sectionName];
    }
}

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

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSString *currentKey = [sectionKeys objectAtIndex:section];
    NSArray *currentNames = [names objectForKey:currentKey];
    return currentNames.count;
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                      reuseIdentifier:CellIdentifier];
    }

    NSString *currentKey = [sectionKeys objectAtIndex:indexPath.section];
    NSArray *currentNames = [names objectForKey:currentKey];

    cell.textLabel.text = [currentNames objectAtIndex:indexPath.row];

    return cell;
}

@end</code>

 

Первое, что следует сделать — это добавить таблицу в наш проект, как это показано в уроке Добавляем таблицу на View. Затем, в методе viewDidLoad после преобразования списка имен в массив мы формируем словарь names, в который сохраняем массивы имен, начинающихся с одной и той же первой буквы. То есть, под ключем @»А» хранятся все имена, которые начинаются с буквы «А». Кроме этого, все ключи (первые буквы имен) мы сохраняем в массиве sectionKeys (именно он является источником данных для полосы индексов). С другой стороны, names представляет из себя словарь, а значит, у него есть метод allKeys, который возвращает массив ключей. Этот массив может быть источником данных для полосы индексов. Но в таком случае, нам бы пришлось его заново сортировать, поскольку метод allKeys возвращает массив элементов не в том порядке, в котором мы добавляли их в names.

 

Как вы могли заметить, данная таблица практиески ни чем не отличается от тех, с которыми мы уже работали. Индексированной ее делает один лишь метод sectionIndexTitlesForTableView:, в котором мы возвращаем массив индексов. А обработку нажатия на индексы, поиск и листание таблицы к нужной секции осуществляет сама таблица.