Skip to content

Instantly share code, notes, and snippets.

@amrox
Last active January 19, 2020 22:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amrox/a5c7f10c18d52c725e3291e3983a7c48 to your computer and use it in GitHub Desktop.
Save amrox/a5c7f10c18d52c725e3291e3983a7c48 to your computer and use it in GitHub Desktop.
AMAsynchronousOperation
#import "AMAsynchronousOperation.h"
@interface AMAsynchronousOperation ()
@property (nonatomic, assign, readwrite) AMAsynchronousOperationState state;
@end
#ifndef AMAsynchronousOperation_FinishIfCancelled
#define AMAsynchronousOperation_FinishIfCancelled() \
if (self.isCancelled) { \
self.state = AMAsynchronousOperationStateFinished; \
return; \
}
#endif
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSUInteger, AMAsynchronousOperationState) {
AMAsynchronousOperationStateReady,
AMAsynchronousOperationStateExecuting,
AMAsynchronousOperationStateFinished,
};
@interface AMAsynchronousOperation : NSOperation
#pragma mark Subclasses
@property (nonatomic, assign, readonly) AMAsynchronousOperationState state;
@end
#import "AMAsynchronousOperation.h"
#import "AMAsynchronousOperation+Private.h"
@implementation AMAsynchronousOperation
- (instancetype)init
{
self = [super init];
if (self) {
_state = AMAsynchronousOperationStateReady;
}
return self;
}
- (BOOL)isAsynchronous
{
return YES;
}
- (BOOL)isReady
{
return super.isReady && AMAsynchronousOperationStateReady == self.state;
}
- (BOOL)isExecuting
{
return AMAsynchronousOperationStateExecuting == self.state;
}
- (BOOL)isFinished
{
return AMAsynchronousOperationStateFinished == self.state;
}
- (void)start
{
if (self.isCancelled) {
self.state = AMAsynchronousOperationStateFinished;
} else {
self.state = AMAsynchronousOperationStateReady;
[self main];
}
}
- (NSString *)keyForState:(AMAsynchronousOperationState)state
{
switch (state) {
case AMAsynchronousOperationStateReady:
return @"isReady";
case AMAsynchronousOperationStateExecuting:
return @"isExecuting";
case AMAsynchronousOperationStateFinished:
return @"isFinished";
}
}
- (void)setState:(AMAsynchronousOperationState)newState
{
if (_state == newState) {
return;
}
AMAsynchronousOperationState oldState = _state;
[self willChangeValueForKey:[self keyForState:oldState]];
[self willChangeValueForKey:[self keyForState:newState]];
[self willChangeValueForKey:@"state"];
_state = newState;
[self didChangeValueForKey:@"state"];
[self didChangeValueForKey:[self keyForState:oldState]];
[self didChangeValueForKey:[self keyForState:newState]];
}
- (void)main
{
AMAsynchronousOperation_FinishIfCancelled();
self.state = AMAsynchronousOperationStateExecuting;
}
@end
@kielgillard
Copy link

Nice. There's a bug in isReady, though. If you're using dependencies, calling super.isReady will return false until all dependencies are completed. So the isReady implementation should probably be something like: return super.isReady && AMAsynchronousOperationStateReady == self.state;

@amrox
Copy link
Author

amrox commented Jan 2, 2020

@kielgillard thanks for pointing that out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment