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

Делегирование в интерфейсе

На сайте есть пример использования такого мощного механизма как делегирование, однако он слабо визуализирован, поэтому неопытному программисту сложно понять, где его использовать. В данном уроке я хочу это продемонстрировать. Для этого нам будет необходим проект, в котором реализована возможность перехода между контроллерами. Велосипед мы изобретать не будем и воспользуемся кодом, с примера Контроллер навигаций (UINavigationController).

 

Давайте внесём минимальные визуальные изменения в класс MyClassViewController и заменим текст кнопкой, по нажатию на которую мы  будем удалять выбранную нами строчку в таблице из класса RootViewController.  Уверен, что удалить компонент UILabel и добавить на форму UIButton у вас не составит труда. Ну и конечно изменим код программы и связи. А так же нам надо будет добавить метод, вызываемый по нажатию на нашу кнопку. Для быстроты предлагаю оставить имена как есть, хотя если Вы хотите переименовать переменную во всём проекте можете воспользоваться Refactor. Интерфейс класса MyClassViewController будет выглядеть так:

 

<code data-result="[object Object]">@interface MyClassViewController : UIViewController {
    UILabel *name;
    NSString *selectedStudent;
    NSInteger currentIndex;
}

@property (nonatomic, retain) IBOutlet UILabel *name;
@property (nonatomic, retain) NSString *selectedStudent;
@property (nonatomic, assign) NSInteger currentIndex;

-(IBAction)deleteCurrentStudent;

@end</code>

 

Теперь давайте рассмотрим реализацию этого же класса.  В нём нам надо описать метод deleteCurrentStudent:

 

<code data-result="[object Object]">-(IBAction)deleteCurrentStudent{
    //Здесь будет код удаления ячейки из таблицы класса RootViewController
}</code>

 

А так же компилятору не понравится строчка:

 

<code data-result="[object Object]">name.text = selectedStudent;</code>

 

мы её заменим на:

 

<code data-result="[object Object]">NSString *title = [NSString stringWithFormat:@"Удалить %@", selectedStudent];
[name setTitle:title forState:UIControlStateNormal];</code>

 

Для того, чтобы удалить студента, нам необходимо достучаться до массива со студентами, который принадлежит другому классу, а именно классу RootViewController. Вот тут-то нам и придётся воспользоваться магией делегирования. В нашем случае классMyClassViewController собирается кого-то оповещать, что студент удалён из базы. Этот “кто-то” – это класс RootViewController. Чтобы этот класс мог реагировать и принимать сообщения на изменения у него должно быть заранее определённое поведение. Такое поведение можно реализовать с помощью протокола. Создадим такой протокол и назовем его studentDelegate, а метод, который будет вызываться назовём deleteStudentFromIndex:. Добавим в интерфейсе класса MyClassViewController описание протокола и переменную, которая будет принимать значение делегата:

 

<code data-result="[object Object]">@protocol studentDelegate &lt;NSObject&gt;
@optional
-(void) deleteStudentFromIndex:(NSInteger)row;
@end

@interface MyClassViewController : UIViewController {
    UIButton *name;
    NSString *selectedStudent;
    NSInteger currentIndex;
    id &lt;studentDelegate&gt; delegate;
}

@property (nonatomic, retain) IBOutlet UIButton *name;
@property (nonatomic, retain) NSString *selectedStudent;
@property (nonatomic, assign) NSInteger currentIndex;
@property (nonatomic, assign) id &lt;studentDelegate&gt; delegate;

-(IBAction)deleteCurrentStudent;

@end</code>

 

И не забудьте синтезировать методы для переменных currentIndex и delegate. А в интерфейсе класса RootViewController в фигурных скобках подключем только что созданный протокол:

 

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

@interface RootViewController : UITableViewController &lt;studentDelegate&gt; {
    NSMutableArray *students;
}

@property (nonatomic, retain) NSMutableArray *students;

@end</code>

 

Обратите внимание на то, что теперь у нас переменная students имеет тип NSMutableArray, так как мы будем из него удалять элементы.
После того как мы определили протокол нам надо в реализацию класса RootViewController добавить метод:

 

<code data-result="[object Object]">-(void)deleteStudentFromIndex:(NSInteger)row{
    [students removeObjectAtIndex:row];
    [self.tableView reloadData];
}</code>

 

В первой строчке мы удаляем из массива элемент, во второй мы принудительно обновляем нашу таблицу.

 

Теперь пришло время вернуться к методу deleteCurrentStudent:

 

<code data-result="[object Object]">-(IBAction)deleteCurrentStudent {
    if(delegate &amp;&amp; [delegate respondsToSelector:@selector(deleteStudentFromIndex:)]){
        [delegate deleteStudentFromIndex:currentIndex];
        [self.navigationController popViewControllerAnimated:YES];
    }
}</code>

 

В первой строчке мы проверяем установлен ли делегат и поддерживает ли делегат метод, который планируем вызвать. Потому что делегат может быть не назначен или назначен класс, в котором не описана реализация метода, который мы хотим вызвать. Если оба условия выполняются — вызываем метод deleteStudentFromIndex и возвращаемся к контроллеру с таблицей.

 

Напоследок нам надо изменить реализацию метода  didSelectRowAtIndexPath. Вот как он должен выглядеть:

 

<code data-result="[object Object]">- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyClassViewController *detailViewController = [[MyClassViewController alloc] 
                                                   initWithNibName:@"MyClassViewController" bundle:nil];
    detailViewController.delegate = self;
    detailViewController.currentIndex = indexPath.row;
    detailViewController.selectedStudent = [students objectAtIndex:indexPath.row];
    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}</code>

 

В нем мы просто установили значения для двух новый переменных, которые добавили раньше.

 

Исходный код программы можно скачать здесь.