实现了并发 NSOperation
,以抽象并帮助创建异步操作。
我们在异步的世界中编码。我们承诺。
-- PromiseKit
每个 iOS 开发人员肯定都会同意这个说法,我们代码的大部分都是高度异步的,这给我们带来了一些挑战。幸运的是,我们有一些机制来组织我们的业务逻辑,将 NSOperation
与 NSOperationQueue
结合使用是其中之一,它功能强大且灵活。
然而,尽管具有很大的灵活性,如果您需要在 NSOperation
上进行异步调用,那就注定要失败了。记住,一个 NSOperation
将在 -main
方法返回后立即完成。所以,您可能会使用信号量或其他类似项来锁定操作,以便在异步调用运行期间将其锁住,否则它将在规定时间内完成。这感觉不太对劲。
实际上,您并不完全注定要失败,由于 NSOperation
提供的出色灵活性,您能够创建一个并发操作,在该操作中您可以完全控制何时将操作视为完成,并且只有当异步调用完成时才完成操作。
实现并发操作并不困难,但您需要对这种类型的每个操作进行一些特定的实现。这是 DRAsyncOperation
的主要原因,它是一个类,实现了使用并发操作所需的基本功能,从而可以在 NSOperation
中使用异步代码。
将位于 DRAsyncOperation
文件夹中的所有文件拖放到您的项目中,然后完成。您还可以将 Xcode 项目作为依赖项导入到您的工作区中。
使用 DRAsyncOperation
实现异步操作非常简单,并且它可能看起来与实现自定义 NSOperation
非常相似。
DRAsyncOperation
类;-asyncTask;
(其中您实现异步代码),您可以将其视为非并发操作的自定义 -main
方法;-finish
来结束操作,这部分与 NSOperation
相比是新的。上述方法在
DRAsyncOperationSubclass.h
中可用。
您也可以使用 DRAsyncBlockOperation
通过简单的块来创建异步操作,这可能看起来与 NSBlockOperation
非常相似。
如果您创建了一个 DRAsyncOperation
的实例并调用 -start
来手动启动操作,您应该注意,由于这些操作是异步的,此调用可能不会在完成前阻塞。如果您想获得类似非并发操作的行为,应在 -start
之后调用 -waitUntilFinished
。
// DRNetworkAsyncOperation.h
#import "DRAsyncOperation.h"
@interface DRNetworkAsyncOperation : DRAsyncOperation
@end
// DRNetworkAsyncOperation.m
#import "DRNetworkAsyncOperation.h"
#import "DRAsyncOperationSubclass.h"
@implementation DRNetworkAsyncOperation
- (void)asyncTask
{
NSURL *githubURL = [NSURL URLWithString:@"https://github.com"];
[[NSURLSession sharedSession] dataTaskWithURL:githubURL
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Do your stuff ...
// When you're done, finish the operation
[self finish];
}];
}
@end
NSOperationQueue *queue;
CLGeocoder *geocoder;
CLLocation *location;
NSOperation *asyncOperation = [DRAsyncBlockOperation asyncBlockOperationWithBlock:^(DRAsyncBlockOperationFinishBlock finish) {
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
// Do your stuff ...
// When you're done, finish the operation
finish();
}];
}];
[queue addOperation:asyncOperation];
Swift 本身支持,您只需要在桥梁头文件中导入相关的头文件。
// If you want to implement async tasks in operations
#import "DRAsyncOperation.h"
#import "DRAsyncOperationSubclass.h"
// If you want to implement async tasks in blocks
#import "DRAsyncBlockOperation.h"
与 Objective-C 相比,Swift 中的块 API 更紧凑。
var queue: NSOperationQueue
var geocoder: CLGeocoder
var location: CLLocation
var asyncOperation: DRAsyncBlockOperation!
asyncOperation = DRAsyncBlockOperation { (finish) -> Void in
// This is automatically checked for you at the beginning of the operation but you could check it during your execution
if asyncOperation.isCancelled() {
finish()
return
}
geocoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Do your stuff ...
// When you're done, finish the operation
finish()
})
}
queue.addOperation(asyncOperation)
DRAsyncOperation 在 MIT 许可证下发布。