NSOperation 与 GCD 更新视图

NSOperation vs GCD for updating view

使用这个有什么区别吗(这是测试用的代码):

dispatch_async(dispatch_get_main_queue(), ^{
                [self.progressBar setProgress:progressValue];
});

而不是这个:

[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
    [self.progressBar setProgress:progressValue];
}];

我在这种情况下使用上面的代码:

NSOperationQueue *progressQueue = [[NSOperationQueue alloc] init];


    [progressQueue addOperationWithBlock:^{
        for (int i = 1; i <= 10; i++) {
            sleep(1);
            float progressValue = (float)i/10.0;

            /* GCD
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.progressBar setProgress:progressValue];
            });
            */
            /* Does this have the same effect as using GCD from above
            [[NSOperationQueue mainQueue] addOperationWithBlock:^
             {
                  [self.progressBar setProgress:progressValue];
             }];
             */
        }
    }];

这两个实际上是一样的。

同样的事情,但不是真的......!

正如@BradLarson 所说 NSOperation vs Grand Central Dispatch

Before GCD, I used a lot of NSOperations / NSOperationQueues within my applications for managing concurrency. However, since I started using GCD on a regular basis, I've almost entirely replaced NSOperations and NSOperationQueues with blocks and dispatch queues. This has come from how I've used both technologies in practice, and from the profiling I've performed on them.

First, there is a nontrivial amount of overhead when using NSOperations and NSOperationQueues. These are Cocoa objects, and they need to be allocated and deallocated. In an iOS application that I wrote which renders a 3-D scene at 60 FPS, I was using NSOperations to encapsulate each rendered frame. When I profiled this, the creation and teardown of these NSOperations was accounting for a significant portion of the CPU cycles in the running application, and was slowing things down. I replaced these with simple blocks and a GCD serial queue, and that overhead disappeared, leading to noticeably better rendering performance. This wasn't the only place where I noticed overhead from using NSOperations, and I've seen this on both Mac and iOS.

Second, there's an elegance to block-based dispatch code that is hard to match when using NSOperations. It's so incredibly convenient to wrap a few lines of code in a block and dispatch it to be performed on a serial or concurrent queue, where creating a custom NSOperation or NSInvocationOperation to do this requires a lot more supporting code. I know that you can use an NSBlockOperation, but you might as well be dispatching something to GCD then. Wrapping this code in blocks inline with related processing in your application leads in my opinion to better code organization than having separate methods or custom NSOperations which encapsulate these tasks.

NSOperations and NSOperationQueues still have very good uses. GCD has no real concept of dependencies, where NSOperationQueues can set up pretty complex dependency graphs. I use NSOperationQueues for this in a handful of cases.

Overall, while I usually advocate for using the highest level of abstraction that accomplishes the task, this is one case where I argue for the lower-level API of GCD. Among the iOS and Mac developers I've talked with about this, the vast majority choose to use GCD over NSOperations unless they are targeting OS versions without support for it (those before iOS 4.0 and Snow Leopard).