Я считаю, что иногда полезно обернуть NSOperation вокруг метода, который запускается таймером, как вы делаете, чтобы воспользоваться преимуществами зависимостей, отмены и других функций, предоставляемых очередью операций. Однако, как правило, нет необходимости запускать таймер в отдельном потоке, а также не требуется, чтобы метод, который вызывает таймер, выполнялся в фоновом потоке. Фактически, большую часть времени он не должен выполняться в фоновом потоке, потому что метод обновляет пользовательский интерфейс. Если это верно и для вас, такая установка должна работать:
#import <Foundation/Foundation.h>
@interface TimerOperation : NSOperation {
@private
NSTimer* _timer;
}
@property (nonatomic, readonly) BOOL isExecuting;
@property (nonatomic, readonly) BOOL isFinished;
@end
(Добавить в собственное состояние, пользовательский конструктор и т. Д.).
@implementation TimerOperation
@synthesize isExecuting = _executing;
@synthesize isFinished = _finished;
- (id) init {
if ((self = [super init])) {
_executing = NO;
_finished = NO;
}
return self;
}
- (void) dealloc {
[_timer release];
[super dealloc];
}
- (BOOL) isConcurrent {
return YES;
}
- (void) finish {
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
- (void) start {
if ([self isCancelled]) {
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
} else {
[self willChangeValueForKey:@"isExecuting"];
[self performSelectorOnMainThread:@selector(main)
withObject:nil
waitUntilDone:NO];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
}
}
- (void) timerFired:(NSTimer*)timer {
if (![self isCancelled]) {
// Whatever you want to do when the timer fires
}
}
- (void) main {
_timer = [[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerFired:)
userInfo:nil
repeats:YES] retain];
}
- (void) cancel {
[_timer invalidate];
[super cancel];
}
@end
Конечно, если основной поток заблокирован (например, из-за длительного сохранения базы данных), вы не увидите срабатывание таймера, но в большинстве случаев это работает нормально.
Вы можете использовать ту же настройку для работы с асинхронными API внутри NSOperations.