В некоторых видах прикладного кода среде Cocoa может быть предписано, что нужно делать.

Однако среда Cocoa — это черный ящик, и поэтому, что и особенно когда в ней будет сделано, не поддается контролю. Прикладной код может выполняться в ответ на некоторое событие, но, в свою очередь, он может инициировать новое событие или цепочку событий. Иногда это приводит к неудачному исходу: аварийному завершению или невыполнению средой Cocoa того, что ей было предписано сделать. Одна из главных причин подобных затруднений заключается в самой цепочке инициируемых событий. Иногда нужно просто выйти из этой цепочки на какое-то время и подождать до тех пор, пока все не установится, а затем продолжить.

Для этого имеется способ, называемый отложенным выполнением. Команда сделать что-нибудь дается среде Cocoa не сразу, а немного позже, когда все установится. Задержка, которая для этого потребуется, может быть короткой ли вообще нулевой, но она делается для того, чтобы дать среде Cocoa возможность завершить какую-нибудь внутреннюю операцию, например, расположение пользовательского интерфейса. В принципе, отложенное выполнение позволяет завершить текущий цикл исполнения, заполнить и развернуть весь текущий стек вызовов, прежде чем продолжить выполнение прикладного кода.

Пользоваться отложенным выполнением вам, скорее всего, придется намного чаще, чем вы предполагаете. С опытом у вас выработается oto6oe чутье на то, когда отложенное выполнение может разрешить возникающие у вас затруднения. В своем коде я обычно реализую отложенное выполнение в трех следующих методах.

 

performSelector:withObject:afterDelay:

Этот метод из класса NSObject упоминался в конце главы 10. Он имеет ограничение на сигнатуру селектора, принимая только один параметров или вообще не принимая параметры. В связи с этим, возможно, придется немного реорганизовать свой код.

 

dispatch_after

Этот метод упоминался в главе 3. Он принимает в качестве параметра блок, а не селектор, что упрощает и повышает удобочитаемость кода.

 

di spat ch_ a syn с

Нередко искомая задержка может быть не больше нуля. В данном случае предпринимается попытка пропустить следующий шаг до тех пор, пока не выяснятся последствия выполнения предыдущего шага. Поэтому достаточно подождать до тех пор, пока ничего не будет происходить. Это можно сделать с помощью метода dispatch_async в той же самой очереди, где все происходит в настоящий момент, а именно: в главной очереди.

Во всех трех рассмотренных выше случаях нужная операция будет выполнена позднее. Это означает, что построчное выполнение кода намеренно нарушается. Следовательно, вызов, выполнение которого отложено, будет последним в своем методе (или блоке), но возвращать значение в результате его исполнения нельзя.

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

- (void) tableView:(UITableView *)tableView

didSelectRowAtlndexPath:(NSIndexPath *)indexPath {

TracksViewController *t =

[[TracksViewController alloc]

initWithMedialtemCollection:(self.albums)[indexPath.row]];

[self.navigationController pushViewController:t animated:YES];

}

К сожалению, невинный, на первый взгляд, вызов метода initWithMedialtem Collection: из класса TracksViewController может быть выполнен не сразу. Поэтому выполнение приложения останавливается с подсвеченной строкой в таблице. Несмотря на то что это происходит недолго, все же это заметно для пользователя. Для того чтобы придать этой задержке ощущение какой-то деятельности, я наделил подкласс, производный от класса UITableViewCell, функцией отображения вертящегося индикатора активности при выборе строки в таблице:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

if (selected) {

[self.activitylndicator startAnimating]; // отобразить и вращать } else {

[self.activitylndicator stopAnimating];            //            скрыть

}

[super setSelected:selected animated:animated];

}

Тем не менее вертящийся индикатор активности вообще не появляется и не вращается. Объясняется это тем, что события запинаются друг о друга. В частности, метод setSelected:animated: из класса UITableViewCell не вызывается до тех пор, пока не завершится метод делегата tableView:didSelectRowAtlndexPath: из класса UITableView. Однако задержка, которую мы пытаемся скрыть, происходит во время выполнения метода tableView:didSelectRowAtlndexPath:. Все дело в том, что этот метод не завершается достаточно быстро.

Здесь на помощь приходит отложенное выполнение! Достаточно переписать метод tab leView:didSelectRowAtlndexPath: таким образом, чтобы он завершался немедленно. Следовательно, метод setSelected:animated: запускается на выполнение сразу и вертящийся индикатор активности появляется на экране. Отложенное выполнение применяется для вызова метода initWithMedialtemCollection: в дальнейшем, когда отображение пользовательского интерфейса стабилизируется.

- (void) tableView:(UITableView *)tableView

didSelectRowAtlndexPath:{NSIndexPath *)indexPath {

// небольшая задержка, позволяющая раскрутиться вертящемуся индикатору double delaylnSeconds = 0.1; dispatch_time_t popTime =

dispatch_time(DISPATCH_TIME_NOW, delaylnSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue() , A(void){

TracksViewController *t =

[[TracksViewController alloc]

initWithMedialtemCollection:(self.albums)[indexPath.row]];

[self.navigationController pushViewController:t animated:YES];

});

}


 

 

 

Добавить комментарий