суббота, 24 октября 2015 г.

35. UITableView UISearchBar NSOperation

В уроке 35 рассматривается организация поиска в таблице UITableView с помощью UISearchBar.
 Рассматривается выделение поиска и обработки данных в фоновый процесс.
Создается класс- наследник UITableViewController. В storyBoard создается NavigationController и UITableViewController.
Созданный класс связывается с контроллером из storyBoard.
Так же создается UISearchBar, аутлет и делегат указывает на базовый контроллер.
Создается класс секций состоящий из названия секции и массива строк входящих в секцию.

@interface TASection : NSObject

@property (strong,nonatomic) NSString *sectionName;
@property(strong,nonatomic) NSMutableArray *itemArray;


@end

Создается массив случайных строк (используется категория-расширения NSString).

@implementation NSString (Random)
+ (NSString *)randomAlphanumericString
{
    NSInteger length=arc4random()%10+5;

    return [self randomAlphanumericStringWithLength:length];
}
+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length
{
    NSString *letters = @"abcdefghijklmnopqrstuvwxyz";
    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
    
    for (int i = 0; i < length; i++) {
        [randomString appendFormat:@"%C", [letters characterAtIndex:arc4random() % [letters length]]];
    }
    
    return randomString;

}

Сортируется этот массив строк с помощью NSSortDescriptor

    NSSortDescriptor *sortDescriptor=[[NSSortDescriptor alloc] initWithKey:@"self" ascending:YES];
    [array sortUsingDescriptors:@[sortDescriptor]];

Создается функция, создающая секции (первая буква строки) и включающая в каждую секцию строки начинающиеся с этой буквы. Так же функция использует фильтр, по которому исключается добавление строк не содержащихся в фильтре.

-(NSArray*) generateSectionsFromArray: (NSArray*) array withFilter: (NSString*) filterString{
    NSString *currentLetter=nil;
    NSMutableArray* sectionArray=[NSMutableArray array];
    
    for (NSString *str in array) {
        if(([filterString length]>0)&&[str rangeOfString:filterString].location==NSNotFound){
            continue;
        }
        NSString *firstletter=[str substringToIndex:1];
        TASection *section=nil;
        if(![currentLetter isEqualToString:firstletter] )
        {
            section=[[TASection alloc] init];
            section.sectionName=firstletter;
            currentLetter=firstletter;
            section.itemArray=[NSMutableArray array];
            [sectionArray addObject:section];
        }
        else
        {
            section= [sectionArray lastObject];;
        }
        [section.itemArray addObject:str];
        
    }
    
    return sectionArray;
}

Для проведения ресурсоемкий расчетов в фоновом процессе и возможности отменить старую операцию (при поступлении новой), добавляем 
@property (strong,nonatomic) NSOperation *currentOperation;

Метод для фоновых вычислений с использованием блоков.

-(void) generateSectionsInBackgroundFromArray: (NSArray*) array withFilter: (NSString*) filterString{
    [self.currentOperation cancel];
    __weak ViewController * weakSelf=self;
    self. currentOperation=[NSBlockOperation blockOperationWithBlock:^{
        NSArray *sectionsArray=[weakSelf generateSectionsFromArray:array withFilter:filterString];
        dispatch_async(dispatch_get_main_queue(), ^{
            weakSelf.sectionArray=sectionsArray;
            [weakSelf.tableView reloadData];
            self.currentOperation=nil;
        });
    }];
    [self.currentOperation start];
}

Для создания  оглавления и ссылок на секции (панельки сбоку) нужно определить метод, 


- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView{
    NSMutableArray *array=[NSMutableArray array];
    for (TASection * section in self.sectionArray){
        [array addObject:section.sectionName];
    }
    return array;
}

а так же определить делегата для UISearchBar в storyboard.

@interface ViewController : UITableViewController <UISearchBarDelegate>

Для  показа кнопки Отмены при начале редактирования, определяем метод

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
    [searchBar setShowsCancelButton:YES animated:YES];
}

Для обработки нажатия клавиши Отмена (например убрать клавиатуру с экрана) определяется следующий метод

-( void) searchBarCancelButtonClicked:(nonnull UISearchBar *)searchBar{
    [searchBar resignFirstResponder];
    [searchBar setShowsCancelButton:NO animated:YES];
}

 Для  обработки каждого изменения в строке поиска обрабатываем следующий метод

-(void) searchBar:(UISearchBar*) searchBar textDidChange:(nonnull NSString *)searchText{
    [self generateSectionsInBackgroundFromArray:self.arrayNames withFilter:searchText];
}

Исходник с тестовым проектом урока 35.

Домашнее задание к уроку 35:

Ученик.

1. Создайте класс студента. У него должны быть свойства: имя, фамилия и год рождения.
2. Генерируйте случайное количество студентов и отобразите их в вашей таблице. (слева имя и фамилия, а справа дата рождения)

Студент.

3. Сгрупируйте студентов по секциям месяцев рождения, то есть все кто родился в январе в одной секции, а если в феврале никто не родился, то и секции такой нет.
4. Внутри секции студенты должны быть отсортированы по имени по алфавиту, а если имена одинаковы, то и по фамилии (подсказка, лучше отсортировать массив вначале по 3 всем параметрам: дата, имя и фамилия)
5. Добавьте индекс бар для быстрого перехода по секциям

Мастер.

6. Добавьте серчбар как в видео, чтобы кнопочка кенсел анимировано добавлялась/уезжала и тд
7. Фильтруйте студентов каждый раз, когда вводится новая буква, причем совпадения ищите как в имени так и в фамилии

Все задания выполнены

Ссылка на исходник программы.

Комментариев нет:

Отправить комментарий