HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Canonical Implementation of a Subclass of NSOperation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
nsoperationcanonicalsubclassimplementation

Problem

I would like to develop a kind of template or canonical implementation for a concurrent subclass of NSOperation.

Edit: there is a related request which implements the NSOperation subclass in Swift.
Requirements:

  • Thread safe API.



  • start shall 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.