Source/TNLRequestOperationQueue.h (34 lines of code) (raw):

// // TNLRequestOperationQueue.h // TwitterNetworkLayer // // Created on 5/23/14. // Copyright © 2020 Twitter, Inc. All rights reserved. // #import <TwitterNetworkLayer/TNLRequestOperation.h> @protocol TNLNetworkObserver; NS_ASSUME_NONNULL_BEGIN // Background request notification and key constants FOUNDATION_EXTERN NSString * const TNLBackgroundRequestOperationDidCompleteNotification; FOUNDATION_EXTERN NSString * const TNLBackgroundRequestURLRequestKey; // NSURLRequest FOUNDATION_EXTERN NSString * const TNLBackgroundRequestResponseKey; // TNLResponse FOUNDATION_EXTERN NSString * const TNLBackgroundRequestURLSessionConfigurationIdentifierKey; // NSString FOUNDATION_EXTERN NSString * const TNLBackgroundRequestURLSessionTaskIdentifierKey; // @(NSUInteger) FOUNDATION_EXTERN NSString * const TNLBackgroundRequestURLSessionSharedContainerIdentifierKey; // NSString /** The `TNLRequestOperationQueue` is the core flow control object of __TNL__ ## TNLRequestOperationQueue Responsibility The operation queue is primarily responsible for flow control: - see `[TNLRequestOperationQueue enqueueRequestOperation:]` - The features `TNLRequestOperationQueue` provides regarding enqueing are: - Queue prioritization - Automatic notifications regarding running network connections - See `TNLNetworkExecutingNetworkConnectionsDidUpdateNotification` - See `[TNLNetwork incrementExecutingNetworkConnections]` and `[TNLNetwork decrementExecutingNetworkConnections]` - Eliciting informative callbacks to `TNLNetworkObserver` - Suspending ## High Level Effectively, the way you use a `TNLRequestOperationQueue` is fairly simple. 1. Create your `TNLRequestOperationQueue` and persist it somehow (or use the `defaultOperationQueue`) - FWIW: Custom `TNLRequestOperationQueue` instances are rarely necessary. 2. Get a `TNLRequestOperation` with a `TNLRequest` conforming object, a `TNLRequestConfiguration` (optional) and a `TNLRequestDelegate` (optional) 3. (Optionally) customize your `TNLRequestOperation`'s properties (such as `[NSOperation dependencies]` and `[TNLRequestOperation priority]` 3. Enqueue your `TNLRequestOperation` ## Background Requests __TNL__ supports executing requests in the background and as such needs a headless mechanism to support handling the completion of those requests. __TNL__ uses an `NSNotification` pattern for notifying interested parties when a background request completes. - `TNLBackgroundRequestOperationDidCompleteNotification` which has some user info values - `TNLBackgroundRequestURLRequestKey` - the `NSURLRequest` of the background request that completed - `TNLBackgroundRequestResponseKey` - the `TNLResponse` encapsulting the result of the request - `TNLBackgroundRequestURLSessionConfigurationIdentifierKey` - The `NSURLSessionConfiguration`'s _identifier_ as an `NSString` - `TNLBackgroundRequestURLSessionTaskIdentifierKey` - An unsigned integer (wrapped in an `NSNumber`) that matches the _taskIdentifier_ of the underlying `NSURLSessionTask` that completed - `TNLBackgroundRequestURLSessionSharedContainerIdentifierKey` - The `NSString` _sharedContainerIdentifier_ of the `NSURLSessionConfiguration` - __TODO:[nobrien]__ - Change this from specifically being a _background_ request notification to a _headless_ request notification. ## TNLRequestOperationQueue categories */ @interface TNLRequestOperationQueue : NSObject /** The default singleton instance of a `TNLRequestOperationQueue`. Easiest option for just sending a request. */ + (instancetype)defaultOperationQueue; /** Default initializer @param identifier The identifier to use for identifying this specific `TNLRequestOperationQueue`. This identifier MUST be unique among all running queues. Must be in URL host form. Any _identifier_ that is not ASCII alpha-numeric with optional `'.'` seperators, is `nil` or is zero _length_ will throw an exception. If an existing`TNLRequestOperationQueue` already has the given identifier, an exception will be thrown. @return A new instance of a `TNLRequestOperationQueue` */ - (instancetype)initWithIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER; /** 'NS_UNAVAILABLE' */ - (instancetype)init NS_UNAVAILABLE; /** 'NS_UNAVAILABLE' */ + (instancetype)new NS_UNAVAILABLE; /** The (preferrably unique) identifier for receiver */ @property (nonatomic, readonly, copy) NSString *identifier; /** The delegate `TNLNetworkObserver` to receive callbacks related to operations that enqueue with the receiver. */ @property (atomic, nullable) id<TNLNetworkObserver> networkObserver; /** Increment the __suspend count__ A `0` __suspend count__ will permit the receiver to execute enqueued requests. Any other __suspend count__ will suspend the receiver. Suspension won't actually pause executing operations, just prevent queued operations from executing. @note `defaultOperationQueue` cannot be suspended */ - (void)suspend; /** Decrement the __suspend count__ @discussion See `suspend` */ - (void)resume; /** Core enqueue method. @warning Never modify an operation object after it has been added to a queue. See `TNLRequestOperation` @param op the `TNLRequestOperation` to enqueue @note Providing `nil` will result in an exception. Providing an opertion that has already been enqueued to a `TNLRequestOperationQueue` will result in an exception. */ - (void)enqueueRequestOperation:(TNLRequestOperation *)op; /** Convenience enqueue method for very simple requests. @param request the `TNLRequest` to enqueue @param completion the completion block @return Returns the `TNLRequestOperation` that was enqueued See `enqueueRequestOperation:` */ - (TNLRequestOperation *)enqueueRequest:(nullable id<TNLRequest>)request completion:(nullable TNLRequestDidCompleteBlock)completion; /** Cancel all enqueued operations Cancel will force the operations to fail (if they haven't yet completed) and will result in the completion callback `[TNLRequestEventHandler tnl_requestOperation:didCompleteWithResponse:]` being called. The error(s) on completion will be a `TNLErrorDomain` _domain_ error with `TNLErrorCodeRequestOperationCancelled` as the _code_. It will also have `TNLErrorCancelSourceKey` and `TNLErrorCancelSourceDescriptionKey` populated in the _userInfo_ and (optionally) the _optionalUnderlyingError_ set as the `NSUnderlyingError` in the _userInfo_. See `TNLErrorCode` @param source The (required) value to set in resulting `TNLResponse` object's _error.userInfo_ for the `TNLErrorCancelSourceKey` key and is the provider of the `TNLErrorCancelSourceDescriptionKey` value @param optionalUnderlyingError The (optional) value to set in resulting `TNLResponse` object's _error.userInfo_ for the `NSUnderlyingError` key See also: `[TNLRequestOperation cancelWithSource:underlyingError:]` */ - (void)cancelAllWithSource:(id<TNLRequestOperationCancelSource>)source underlyingError:(nullable NSError *)optionalUnderlyingError; /** Cancel the operation. Calls `cancelAllWithSource:underlyingError:` with `nil` for the _optionalUnderlyingError_ */ - (void)cancelAllWithSource:(id<TNLRequestOperationCancelSource>)source; @end #if TARGET_OS_IPHONE // == IOS + WATCH + TV /** __TNLRequestOperationQueue (Background)__ Class method for handling a background `NSURLSession` completing their events when the app wasn't running */ @interface TNLRequestOperationQueue (Background) #pragma twitter startignorestylecheck /** The class method used for handling a background `NSURLSession` competing their events when the app wasn't running Have your `UIApplicationDelegate` implement `application:handleEventsForBackgroundURLSession:completionHandler:` and in that handler call this method for handling the background events via __TNL__. For best results, be sure your reusable `TNLRequestOperationQueue`s are all configured properly before calling this method. __Example:__ - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(dispatch_block_t)completionHandler { [self ensureRequestOperationQueuesAreConfigured]; // optional if (![TNLRequestOperationQueue handleBackgroundURLSessionEvents:identifier completionHandler:completionHandler]) { BOOL handled = NO; // ... // Custom work // ... if (!handled) { completionHandler(); } } } @param identifier The `NSURLSessionConfigurationIdentifier` of the background `NSURLSession` to handle @param completionHandler The completionHandler needed to call when the background `NSURLSession` has completed its events @return `YES` if the events will be handled, `NO` if the events won't be handled by __TNL__ */ + (BOOL)handleBackgroundURLSessionEvents:(nullable NSString *)identifier completionHandler:(dispatch_block_t)completionHandler; #pragma twitter endignorestylecheck @end #endif NS_ASSUME_NONNULL_END