Чтение онлайн

ЖАНРЫ

iOS. Приемы программирования

Нахавандипур Вандад

Шрифт:

Current Thread = <NSThread: 0x6805c20>{name = (null), num = 3}

Main Thread = <NSThread: 0x68 10260>{name = (null), num = 1}

Current Thread = <NSThread: 0x6b2d1d0>{name = (null), num = 4}

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

Main thread is here

[Running_Tasks_Asynchronously_with_OperationsAppDelegate firstOperationEntry: ]

[Running_Tasks_Asynchronously_with_OperationsAppDelegate secondOperationEntry: ]

Parameter Object = 111

Main Thread = <NSThread: 0x68 10260>{name = (null), num = 1}

Current Thread = <NSThread: 0x68247c0>{name = (null), num = 3}

Parameter Object = 222

Main Thread = <NSThread: 0x68 10260>{name = (null), num = 1}

Current Thread = <NSThread: 0x6819b00>{name = (null), num = 4}

Очевидно,

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

Если бы вы создавали подклассы от NSOperation и добавляли в операционную очередь экземпляры нового класса, то ситуация складывалась бы несколько иначе. Не забывайте о некоторых моментах.

Если обычные операции, являющиеся подклассами от NSOperation, добавлять в операционную очередь, то они будут работать асинхронно. Поэтому необходимо переопределить метод экземпляра isConcurrent, относящийся к классу NSOperation, и возвратить значение YES.

Необходимо подготовить операцию к отмене, периодически проверяя значение метода isCancelled при осуществлении основной задачи операции, а также в методе start еще до запуска самой операции. В таком случае метод start вызывается операционной очередью после того, как операция будет добавлена в очередь. В этом методе проверяется, не отменена ли операция. Это делается с помощью метода isCancelled. Если операция отменена, просто верните такое значение от метода start. В противном случае вызовите метод main из метода start.

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

Переопределите методы isFinished и isExecuting операции и верните соответствующие логические (BOOL) значения, показывающие, завершена операция или продолжается в настоящий момент.

Вот объявление операции (.h-файл):

#import <Foundation/Foundation.h>

@interface SimpleOperation: NSOperation

/* Выделенный инициализатор */

— (id) initWithObject:(NSObject *)paramObject;

@end

Реализация операции такова:

#import «SimpleOperation.h»

@implementation SimpleOperation

— (instancetype) init {

return([self initWithObject:@123]);

}

— (instancetype) initWithObject:(NSObject *)paramObject{

self = [super init];

if (self!= nil){

/* Сохраните
эти значения для главного метода. */

_givenObject = paramObject;

}

return(self);

}

— (void) main {

@try {

@autoreleasepool {

/* Сохраняем здесь локальную переменную, которая должна быть

установлена в YES всякий раз, когда мы завершаем

выполнение задачи. */

BOOL taskIsFinished = NO;

/* Создаем здесь цикл while, существующий лишь в том случае,

когда переменная taskIsFinished устанавливается в YES

или операция отменяется. */

while (taskIsFinished == NO &&

[self isCancelled] == NO){

/* Здесь выполняется задача. */

NSLog(@"%s", __FUNCTION__);

NSLog(@"Parameter Object = %@", givenObject);

NSLog(@"Main Thread = %@", [NSThread mainThread]);

NSLog(@"Current Thread = %@", [NSThread currentThread]);

/* Очень важно. Здесь мы можем выйти из цикла, по-прежнему

соблюдая правила, по которым отменяются операции. */

taskIsFinished = YES;

}

/* Соответствие KVO. Генерируем требуемые уведомления KVO. */

[self willChangeValueForKey:@"isFinished"];

[self willChangeValueForKey:@"isExecuting"];

finished = YES;

executing = NO;

[self didChangeValueForKey:@"isFinished"];

[self didChangeValueForKey:@"isExecuting"];

}

}

@catch (NSException * e) {

NSLog(@"Exception %@", e);

}

}

— (BOOL) isConcurrent{

return YES;

}

@end

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

Поделиться с друзьями: