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

Обсуждение

Обсуждение

Выйти из таймера не составляет труда — можно просто вызвать метод экземпляра invalidate, относящийся к таймеру. После вызова этого метода таймер больше не будет инициировать никаких событий в своем целевом объекте.

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

— (void) threadEntryPoint{
@autoreleasepool {
NSLog(@"Thread Entry Point");
while ([[NSThread currentThread] isCancelled] == NO){
[NSThread sleepForTimeInterval:4];
NSLog(@"Thread Loop");
}
NSLog(@"Thread Finished");
}
}
— (void) stopThread{
NSLog(@"Cancelling the Thread");
[self.myThread cancel];
NSLog(@"Releasing the thread");
self.myThread = nil;
}
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.myThread = [[NSThread alloc]
initWithTarget: self
selector:@selector(threadEntryPoint)
object: nil];
[self performSelector:@selector(stopThread)
withObject: nil
afterDelay:3.0f];
[self.myThread start];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}

Данный код создает экземпляр класса NSThread и немедленно запускает поток. Поток в каждом цикле проводит 4 секунды в спящем режиме, а потом переходит к выполнению своей задачи. Тем не менее, прежде чем поток будет запущен, мы вызываем метод stopThread, относящийся к (написанному нами) контроллеру вида; это делается с трехсекундной задержкой. Данный метод вызывает метод cancel, относящийся к потоку, пытаясь заставить поток выйти из своего цикла. Теперь запустим приложение и посмотрим, что выводится в окне консоли:


Thread Entry Point
Cancelling the Thread
Releasing the thread
Thread Loop
Thread Finished

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

— (void) threadEntryPoint{
@autoreleasepool {
NSLog(@"Thread Entry Point");
while ([[NSThread currentThread] isCancelled] == NO){
[NSThread sleepForTimeInterval:4];
if ([[NSThread currentThread] isCancelled] == NO){
NSLog(@"Thread Loop");
}
}
NSLog(@"Thread Finished");
}
}
— (void) stopThread{
NSLog(@"Cancelling the Thread");
[self.myThread cancel];
NSLog(@"Releasing the thread");
self.myThread = nil;
}
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.myThread = [[NSThread alloc]
initWithTarget: self
selector:@selector(threadEntryPoint)
object: nil];
[self performSelector:@selector(stopThread)
withObject: nil
afterDelay:3.0f];
[self.myThread start];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}

Оглавление книги

Оглавление статьи/книги

Генерация: 0.050. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз