TestsTested | ✓ |
LangLanguage | Obj-CObjective C |
License | MIT |
ReleasedLast Release | Mar 2017 |
Maintained by Nick Kuhne.
TWGOperations
is a library for iOS and Mac OS X. It's built on top of NSOperation, providing concurrency and code organization to an application.
The creation of this library was directly inspired from a talk given at Apple WWDC 2015. Video , Example Project Full credit is given the the Apple team for the vision of an Operation centric application.
This library provides tools for quickly and easily implementing structured asynchronous tasks and great concurrency management using Apples NSOperation
suite. But it also prescribes a method of implementation and usage. and we believe that there are good and bad ways of using both NSOperation
and TWGOperation
\ TWGGroupOperation
libraries.
We have found that the TWGOperation
library provides a simple way to remove complex tasks from view controllers, a good interface for unit testing, and an approachable way to learn concurrency and threading.
Want to have a quick look at the sweet sample project written using the TWGOperation
library?
Try out the TWGOperations Example project using CocoaPods
In your terminal: pod try TWGOperations
A TWGOperation
is the foundation of this library. If provides two simple features:
NSOperation
, a TWGOperation
will not complete at the end of the execution method, the developer must explicitly call - (void)finish
to notify the NSOperationQueue
that it no longer needs to execute.TWGOperation
uses the delegate pattern to inform a caller of completion or failure@interface TWGOperation : NSOperation
@property (nonatomic, weak) id<TWGOperationDelegate> delegate;
@end
@interface TWGOperation (SubclassingHooks)
/*
Override this to implement execution
*/
- (void)execute;
/*
TWGOperation subclasses must call this to complete execution of the operation
*/
- (void)finish;
@end
A TWGOperation
can be added to a operation queue and executed by:
MyOperationSubclass *operation = [[MyOperationSubclass alloc] init];
[[NSOperationQueue mainQueue] addOperation:operation];
A TWGOperation
use a delegate to inform a caller of completion or failure
@protocol TWGOperationDelegate <NSObject>
- (void)operation:(nonnull TWGOperation *)operation didCompleteWithResult:(nullable id)result NS_SWIFT_NAME(operationDidComplete(operation:withResult:));
- (void)operation:(nonnull TWGOperation *)operation didFailWithError:(nullable NSError *)error NS_SWIFT_NAME(operationDidFail(operation:withError:));
@end
The developer is afforded quick access to both - (void)finish
and the TWGOperationDelegate
protocol methods using:
@interface TWGOperation (QuickDelegate)
/*
Convenience completion
Subclasses should use these as short hand for the process:
1. Inform delegate of complete or fail
2. -finish
*/
- (void)finishWithResult:(id _Nullable)result NS_SWIFT_NAME(finish(withResult:));
- (void)finishWithError:(NSError * _Nullable)error NS_SWIFT_NAME(finish(withError:));
@end
This is the preferred method of completion and should be used even if no error or result is needed.
[self finishWithResult:nil];
or
[self finishWithError:nil];
A TWGGroupOperation
is a subclass of TWGOperation
which encapsulates operations and needs no - (void)execute
method.
This is done by executing NSOperation
or TWGOperation
subclasses on an internal NSOperationQueue
@interface TWGGroupOperation : TWGOperation
@property (nonatomic, strong, readonly) NSOperationQueue *operationQueue;
/*
initWithOperations: adds operations passed to the operationQueue
subclasses need create sub-operations then [super initWithOperations:]
to have them execute
*/
- (instancetype)initWithOperations:(NSArray<NSOperation *> *)operations;
/*
Subclasses of TWGGroupOperation SHOULD NOT override -execute
See TWGOperation for further subclassing instructions
*/
- (void)execute NS_UNAVAILABLE;
@end
A TWGGroupOperation
is designed to be subclassed and respond to the delegate callbacks of its sub-operations
See the TWGOperation_Example
project for examples.
A TWGGroupOperation
can be added to a operation queue and executed by in the same way a TWGOperation
is:
MyGroupOperationSubclass *operation = [[MyGroupOperationSubclass alloc] init];
[[NSOperationQueue mainQueue] addOperation:operation];
The Flickr REST API is a great example of a rest API that requires several chained API calls to retrieve the final product
A Call for the endpoint:
https://api.flickr.com/services/rest/?method=flickr.photos.getRecent
results in an array of objects similar to:
{
"id": "30379955494",
"owner": "86866994@N00",
"secret": "5c84551928",
"server": "5731",
"farm": 6,
"title": "Frosty leaves",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
}
to get URL's for photos you can call:
https://api.flickr.com/services/rest/?method=flickr.photos.getSizes&photo_id=30379955494
resulting in something like:
{
sizes = {
size = (
{
height = 75;
label = Square;
media = photo;
source = "https://farm6.staticflickr.com/5791/30413623884_ae2f143b5a_s.jpg";
url = "https://www.flickr.com/photos/145345660@N03/30413623884/sizes/sq/";
width = 75;
},
{
height = 528;
label = Large;
media = photo;
source = "https://farm6.staticflickr.com/5791/30413623884_ae2f143b5a_b.jpg";
url = "https://www.flickr.com/photos/145345660@N03/30413623884/sizes/l/";
width = 1024;
}
);
};
stat = ok;
}
which gives us the URL's needed to fetch any individual image.
The Flickr flickr.photos.getRecent
API method returns a first page on 100 items.
So to fetch the first 100 images in the recent photos list, you need to perform
flickr.photos.getRecent
flickr.photos.getSizes
https://www.flickr.com/photos/id/sizes/l/
TWGOperaitons can help to alleviate this burden by providing both the scheduling and dependancy of an NSOperation, as well as the the error checking and retrying required when dealing with any network request.
Refer to the FetchFlickrFeedOperation
for further details about how to implement a solution.
A test suite is available as part of the TWGOperation_Example
project available through CocoaPods.
Proudly, Nicholas Kuhne, [email protected]
TWGOperations is available under the MIT license. See the LICENSE file for more info.