Skip to content

Commit

Permalink
[core] Add back NIOperations.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 319296899
  • Loading branch information
Jeff Verkoeyen authored and material-automation committed Jul 1, 2020
1 parent 9765b24 commit c5a1c1f
Show file tree
Hide file tree
Showing 3 changed files with 340 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/core/src/NIOperations+Subclassing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Copyright 2011-2014 NimbusKit
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "NIOperations.h"

@interface NIOperation()
@property (strong) NSError* lastError;
@end
209 changes: 209 additions & 0 deletions src/core/src/NIOperations.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
//
// Copyright 2011-2014 NimbusKit
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#import "NIPreprocessorMacros.h" /* for weak */

@class NIOperation;

typedef void (^NIOperationBlock)(NIOperation* operation);
typedef void (^NIOperationDidFailBlock)(NIOperation* operation, NSError* error);

/**
* For writing code that runs concurrently.
*
* @ingroup NimbusCore
* @defgroup Operations Operations
*
* This collection of NSOperation implementations is meant to provide a set of common
* operations that might be used in an application to offload complex processing to a separate
* thread.
*/

@protocol NIOperationDelegate;

/**
* A base implementation of an NSOperation that supports traditional delegation and blocks.
*
* <h2>Subclassing</h2>
*
* A subclass should call the operationDid* methods to notify the delegate on the main thread
* of changes in the operation's state. Calling these methods will notify the delegate and the
* blocks if provided.
*
* @ingroup Operations
*/
@interface NIOperation : NSOperation

@property (weak) id<NIOperationDelegate> delegate;
@property (readonly, strong) NSError* lastError;
@property (assign) NSInteger tag;

@property (copy) NIOperationBlock didStartBlock;
@property (copy) NIOperationBlock didFinishBlock;
@property (copy) NIOperationDidFailBlock didFailWithErrorBlock;
@property (copy) NIOperationBlock willFinishBlock;

- (void)didStart;
- (void)didFinish;
- (void)didFailWithError:(NSError *)error;
- (void)willFinish;

@end

/**
* The delegate protocol for an NIOperation.
*
* @ingroup Operations
*/
@protocol NIOperationDelegate <NSObject>
@optional

/** @name [NIOperationDelegate] State Changes */

/** The operation has started executing. */
- (void)nimbusOperationDidStart:(NIOperation *)operation;

/**
* The operation is about to complete successfully.
*
* This will not be called if the operation fails.
*
* This will be called from within the operation's runloop and must be thread safe.
*/
- (void)nimbusOperationWillFinish:(NIOperation *)operation;

/**
* The operation has completed successfully.
*
* This will not be called if the operation fails.
*/
- (void)nimbusOperationDidFinish:(NIOperation *)operation;

/**
* The operation failed in some way and has completed.
*
* operationDidFinish: will not be called.
*/
- (void)nimbusOperationDidFail:(NIOperation *)operation withError:(NSError *)error;

@end


// NIOperation

/** @name Delegation */

/**
* The delegate through which changes are notified for this operation.
*
* All delegate methods are performed on the main thread.
*
* @fn NIOperation::delegate
*/


/** @name Post-Operation Properties */

/**
* The error last passed to the didFailWithError notification.
*
* @fn NIOperation::lastError
*/


/** @name Identification */

/**
* A simple tagging mechanism for identifying operations.
*
* @fn NIOperation::tag
*/


/** @name Blocks */

/**
* The operation has started executing.
*
* Performed on the main thread.
*
* @fn NIOperation::didStartBlock
*/

/**
* The operation has completed successfully.
*
* This will not be called if the operation fails.
*
* Performed on the main thread.
*
* @fn NIOperation::didFinishBlock
*/

/**
* The operation failed in some way and has completed.
*
* didFinishBlock will not be executed.
*
* Performed on the main thread.
*
* @fn NIOperation::didFailWithErrorBlock
*/

/**
* The operation is about to complete successfully.
*
* This will not be called if the operation fails.
*
* Performed in the operation's thread.
*
* @fn NIOperation::willFinishBlock
*/


/**
* @name Subclassing
*
* The following methods are provided to aid in subclassing and are not meant to be
* used externally.
*/

/**
* On the main thread, notify the delegate that the operation has begun.
*
* @fn NIOperation::didStart
*/

/**
* On the main thread, notify the delegate that the operation has finished.
*
* @fn NIOperation::didFinish
*/

/**
* On the main thread, notify the delegate that the operation has failed.
*
* @fn NIOperation::didFailWithError:
*/

/**
* In the operation's thread, notify the delegate that the operation will finish successfully.
*
* @fn NIOperation::willFinish
*/
111 changes: 111 additions & 0 deletions src/core/src/NIOperations.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//
// Copyright 2011-2014 NimbusKit
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "NIOperations.h"

#import "NIDebuggingTools.h"
#import "NIPreprocessorMacros.h"
#import "NIOperations+Subclassing.h"

#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "Nimbus requires ARC support."
#endif

@implementation NIOperation

- (void)dealloc {
// For an unknown reason these block objects are not released when the NIOperation is deallocated
// with ARC enabled.
_didStartBlock = nil;
_didFinishBlock = nil;
_didFailWithErrorBlock = nil;
_willFinishBlock = nil;
}

#pragma mark - Initiate delegate notification from the NSOperation

- (void)didStart {
[self performSelectorOnMainThread:@selector(onMainThreadOperationDidStart)
withObject:nil
waitUntilDone:[NSThread isMainThread]];
}

- (void)didFinish {
[self performSelectorOnMainThread:@selector(onMainThreadOperationDidFinish)
withObject:nil
waitUntilDone:[NSThread isMainThread]];
}

- (void)didFailWithError:(NSError *)error {
self.lastError = error;

[self performSelectorOnMainThread:@selector(onMainThreadOperationDidFailWithError:)
withObject:error
waitUntilDone:[NSThread isMainThread]];
}

- (void)willFinish {
if ([self.delegate respondsToSelector:@selector(nimbusOperationWillFinish:)]) {
[self.delegate nimbusOperationWillFinish:self];
}

if (nil != self.willFinishBlock) {
self.willFinishBlock(self);
}
}

#pragma mark - Main Thread

- (void)onMainThreadOperationDidStart {
// This method should only be called on the main thread.
NIDASSERT([NSThread isMainThread]);

if ([self.delegate respondsToSelector:@selector(nimbusOperationDidStart:)]) {
[self.delegate nimbusOperationDidStart:self];
}

if (nil != self.didStartBlock) {
self.didStartBlock(self);
}
}

- (void)onMainThreadOperationDidFinish {
// This method should only be called on the main thread.
NIDASSERT([NSThread isMainThread]);

if ([self.delegate respondsToSelector:@selector(nimbusOperationDidFinish:)]) {
[self.delegate nimbusOperationDidFinish:self];
}

if (nil != self.didFinishBlock) {
self.didFinishBlock(self);
}
}

- (void)onMainThreadOperationDidFailWithError:(NSError *)error {
// This method should only be called on the main thread.
NIDASSERT([NSThread isMainThread]);

if ([self.delegate respondsToSelector:@selector(nimbusOperationDidFail:withError:)]) {
[self.delegate nimbusOperationDidFail:self withError:error];
}

if (nil != self.didFailWithErrorBlock) {
self.didFailWithErrorBlock(self, error);
}
}

@end

0 comments on commit c5a1c1f

Please sign in to comment.