patternMinor
Canonical Implementation of a Subclass of NSOperation
Viewed 0 times
nsoperationcanonicalsubclassimplementation
Problem
I would like to develop a kind of template or canonical implementation for a concurrent subclass of
Edit: there is a related request which implements the NSOperation subclass in Swift.
Requirements:
References:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html
Solution
So far, I came up with this solution:
```
#import
/**
Canonical, Concurrent Subclass of NSOperation
*/
typedef void (^completion_block_t)(id result);
@interface MyOperation : NSOperation
// Designated Initializer
// For the sake of testing, parameter count equals the duration in 1/10 seconds until the task is fininshed.
@property (nonatomic, readonly) id result;
@property (nonatomic, copy) completion_block_t completionHandler;
@end
@implementation MyOperation {
BOOL _isExecuting;
BOOL _isFinished;
dispatch_queue_t _syncQueue;
int _count;
id _result;
completion_block_t _completionHandler;
id _self; // immortality
}
{
self = [super init];
if (self) {
_count = count;
_syncQueue = dispatch_queue_create("op.sync_queue", NULL);
_completionHandler = [completionHandler copy];
}
return self;
}
__block id result;
dispatch_sync(_syncQueue, ^{
result = _result;
});
return result;
}
{
dispatch_async(_syncQueue, ^{
if (!self.isCancelled && !_isFinished && !_isExecuting) {
self.isExecuting = YES;
_self = self; // make self immortal for the duration of the task
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSOperation.Edit: there is a related request which implements the NSOperation subclass in Swift.
Requirements:
- Thread safe API.
startshall only start the task once, otherwise it has no effect.
- The NSOperation object shall be immortal while the task is executing.
References:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html
Solution
So far, I came up with this solution:
```
#import
/**
Canonical, Concurrent Subclass of NSOperation
*/
typedef void (^completion_block_t)(id result);
@interface MyOperation : NSOperation
// Designated Initializer
// For the sake of testing, parameter count equals the duration in 1/10 seconds until the task is fininshed.
- (id)initWithCount:(int)count completion:(completion_block_t)completioHandler;
@property (nonatomic, readonly) id result;
@property (nonatomic, copy) completion_block_t completionHandler;
@end
@implementation MyOperation {
BOOL _isExecuting;
BOOL _isFinished;
dispatch_queue_t _syncQueue;
int _count;
id _result;
completion_block_t _completionHandler;
id _self; // immortality
}
- (id)initWithCount:(int)count completion:(completion_block_t)completionHandler
{
self = [super init];
if (self) {
_count = count;
_syncQueue = dispatch_queue_create("op.sync_queue", NULL);
_completionHandler = [completionHandler copy];
}
return self;
}
- (id) result {
__block id result;
dispatch_sync(_syncQueue, ^{
result = _result;
});
return result;
}
- (void) start
{
dispatch_async(_syncQueue, ^{
if (!self.isCancelled && !_isFinished && !_isExecuting) {
self.isExecuting = YES;
_self = self; // make self immortal for the duration of the task
dispatch_async(dispatch_get_global_queue(0, 0), ^{
Solution
- (id)initWithCount:(int)count completion:(completion_block_t)completioHandler;There's a typo here, a missing "n" in the last argument.
- (id)initWithCount:(int)count completion:(completion_block_t)completionHandler
{
- (id) result {
- (void) start
{This inconsistency is really bothersome to me. The opening bracket should either be on the same line or the next line, but do it consistently. Personally, I prefer the opening bracket on the same line as it looks better when the methods are collapsed in Xcode.
if (!self.isCancelled && !_isFinished && !_isExecuting) {
self.isExecuting = YES;This inconsistency also bothers me, and it's not immediately clear why it's done. In fact, even as a season Objective-C programmer, I'm confused as to what would actually happen here when you do
self.isExecuting = YES;Normally, you'd do
self.isExecuting = YES; because you've defined isExecuting as a property, and what is actually done is more akin to this:[self setIsExecuting:YES];But you've not defined
isExecuting as a full property, but rather you've defined _isExecuting as an instance variable and created setIsExecuting:(BOOL)isExecuting as a method.I don't rightly know without just running the code what would or should happen here.
So the solution is to either define
isExecuting as a property so it's more clear what self.isExecuting = YES; would actually do, or to change your self.isExecuting = YES; to either _isExecuting = YES; or [self setIsExecuting:YES]; depending on the intent.Code Snippets
- (id)initWithCount:(int)count completion:(completion_block_t)completioHandler;- (id)initWithCount:(int)count completion:(completion_block_t)completionHandler
{
- (id) result {
- (void) start
{if (!self.isCancelled && !_isFinished && !_isExecuting) {
self.isExecuting = YES;[self setIsExecuting:YES];Context
StackExchange Code Review Q#36632, answer score: 6
Revisions (0)
No revisions yet.