// // DTOperation.m // DTOperation // // Created by Diogo on 10/14/15. // Copyright © 2015 Diogo Tridapalli. All rights reserved. // #import "DTOperation.h" static NSString * const kStateKeyPath = @"state"; static inline BOOL IsValidStateTransition(DTOperationState fromState, DTOperationState toState) { if (fromState == toState) { NSLog(@"Inconsistent state, from %ld to %ld", (long)fromState, (long)toState); return NO; } switch (fromState) { case kDTOperationStateReady: case kDTOperationStateExecuting: return toState > fromState; case kDTOperationStateFinished: case kDTOperationStateCanceled: default: return NO; } } @interface DTOperation (){ DTOperationState _state; } @property (readwrite) DTOperationState state; @end @implementation DTOperation // use the KVO mechanism to indicate that changes to "state" affect other properties as well + (NSSet *)keyPathsForValuesAffectingIsReady { return [NSSet setWithObject:kStateKeyPath]; } + (NSSet *)keyPathsForValuesAffectingIsExecuting { return [NSSet setWithObject:kStateKeyPath]; } + (NSSet *)keyPathsForValuesAffectingIsFinished { return [NSSet setWithObject:kStateKeyPath]; } + (NSSet *)keyPathsForValuesAffectingIsCanceled { return [NSSet setWithObject:kStateKeyPath]; } - (DTOperationState)state { @synchronized(self) { return _state; } } - (void)setState:(DTOperationState)state { @synchronized(self) { if (NO == IsValidStateTransition(_state, state)) { return; } [self willChangeValueForKey:kStateKeyPath]; _state = state; [self didChangeValueForKey:kStateKeyPath]; } } + (BOOL)automaticallyNotifiesObserversOfState { return NO; } - (BOOL)isReady { return self.state == kDTOperationStateReady && [super isReady]; } - (BOOL)isExecuting { return self.state == kDTOperationStateExecuting; } - (BOOL)isFinished { return self.state >= kDTOperationStateFinished; } - (BOOL)isCancelled { return self.state == kDTOperationStateCanceled; } - (void)start { if (self.state != kDTOperationStateReady) { return; } self.state = kDTOperationStateExecuting; [self execute]; } - (void)execute { [self finish]; } - (void)cancel { self.state = kDTOperationStateCanceled; } - (void)finish { self.state = kDTOperationStateFinished; } @end