我非常喜欢块,但没有将它们用于并发性。在谷歌搜索之后,我把这个想法拼凑在一起,把我学到的一切都藏在一个地方。目标是在后台执行一个块,当它完成后,执行另一个块(如UIView动画).
- (NSOperation *)executeBlock:(void (^)(void))block completion:(void (^)(BOOL finished))completion {
NSOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:block];
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
completion(blockOperation.isFinished);
}];
[completionOperation addDependency:blockOperation];
[[NSOperationQueue mainQueue] addOperation:completionOperation];
NSOperationQueue *backgroundOperationQueue = [[NSOperationQueue alloc] init];
[backgroundOperationQueue addOperation:blockOperation];
return blockOperation;
}
- (void)testIt {
NSMutableString *string = [NSMutableString stringWithString:@"tea"];
NSString *otherString = @"for";
NSOperation *operation = [self executeBlock:^{
NSString *yetAnother = @"two";
[string appendFormat:@" %@ %@", otherString, yetAnother];
} completion:^(BOOL finished) {
// this logs "tea for two"
NSLog(@"%@", string);
}];
NSLog(@"keep this operation so we can cancel it: %@", operation);
}我的问题是:
谢谢。
发布于 2012-07-06 05:17:00
我不是NSOperation或NSOperationQueues方面的专家,但我认为下面的代码更好一些,尽管我认为它还有一些警告。可能对某些目的来说已经足够了,但并不是并发的通用解决方案:
- (NSOperation *)executeBlock:(void (^)(void))block
inQueue:(NSOperationQueue *)queue
completion:(void (^)(BOOL finished))completion
{
NSOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:block];
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
completion(blockOperation.isFinished);
}];
[completionOperation addDependency:blockOperation];
[[NSOperationQueue currentQueue] addOperation:completionOperation];
[queue addOperation:blockOperation];
return blockOperation;
}现在让我们使用它:
- (void)tryIt
{
// Create and configure the queue to enqueue your operations
backgroundOperationQueue = [[NSOperationQueue alloc] init];
// Prepare needed data to use in the operation
NSMutableString *string = [NSMutableString stringWithString:@"tea"];
NSString *otherString = @"for";
// Create and enqueue an operation using the previous method
NSOperation *operation = [self executeBlock:^{
NSString *yetAnother = @"two";
[string appendFormat:@" %@ %@", otherString, yetAnother];
}
inQueue:backgroundOperationQueue
completion:^(BOOL finished) {
// this logs "tea for two"
NSLog(@"%@", string);
}];
// Keep the operation for later uses
// Later uses include cancellation ...
[operation cancel];
}对你的问题的一些回答:
self.isCancelled并提前返回。参见这条线,这是一个很好的例子。在当前的示例中,您无法从您提供的生成NSBlockOperation的块中检查操作是否已被取消,因为当时还没有这样的操作。在调用块时取消NSBlockOperation显然是可能的,但累赘是可能的。NSBlockOperation是针对特定的简单情况的。如果需要取消,则最好将NSOperation :)子类化。)background queue,这样您就不需要为每个操作创建一个,并且可以选择使用哪个队列来运行您的内容:)string atomic。您不应该忘记的一件事是,如果您向队列提供了几个操作,它们可能不会按该顺序运行(必然),因此您可能会在string中得到一条非常奇怪的消息。如果需要一次运行一个操作,则可以在开始对操作进行排队之前执行:[backgroundOperation setMaxConcurrentOperationCount:1];。然而,在文档中有一个值得阅读的注释:
附加操作队列行为操作队列根据其优先级和就绪性执行其排队操作对象。如果所有排队操作对象都具有相同的优先级,并准备好在将它们放入队列时执行--也就是说,它们的isReady方法返回是的--它们将按照提交到队列的顺序执行。对于最大并发操作数设置为1的队列,这等于串行队列。但是,您不应该依赖于操作对象的串行执行。操作准备状态的更改可以更改结果的执行顺序。发布于 2012-06-13 07:22:17
您不应该为每个NSOperationQueue调用创建一个新的executeBlock:completion:。这是昂贵的,而且这个API的用户无法控制一次执行多少次操作。
如果要返回NSOperation实例,则应该由调用方决定将它们添加到哪个队列。但是在这一点上,您的方法并没有做任何有用的事情,调用方也可以自己创建NSBlockOperation。
如果您只想要一种简单而简单的方法在后台拆分一个块并在它完成时执行一些代码,那么使用dispatch_*函数进行一些简单的GCD调用可能会更好。例如:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do your background work
// ...
// now execute the 'completion' code.
// you often want to dispatch back to the main thread to update the UI
// For example:
dispatch_async(dispatch_get_main_queue(), ^{
// update UI, etc.
myLabel.text = @"Finished";
});
});发布于 2018-07-27 08:59:23
没有必要设置一个块来在完成时运行并添加类似的依赖项。与所有NSBlockOperation子类一样,NSOperation子类已经具有一个completionBlock属性,该属性将在块完成其工作后自动运行:
@property(copy) void (^completionBlock)(void);当完成块移动到finished状态时,将运行完成块。
https://stackoverflow.com/questions/11009027
复制相似问题