1

我是异步回调的新手,并且得到了不同的建议。我需要执行异步回调,经过数小时的研究,我仍然不知道我应该使用块还是 GCD 和队列。欢迎任何指点。

好的。所以我真正要问的是:

“为了使用‘异步’回调,我需要使用 GCD 和队列吗?”

我从答案中收集到的是答案是YES。绝对是GCDblocks内的队列

我的困惑源于这样一个事实,即我得到了我所需要的只是一个块的方向,如下面的代码:

[UIView animateWithDuration:.4f
                 animations:^{
                     flashView.alpha = 0.f;
                 }
                 completion:^(BOOL finished){
                     [flashView removeFromSuperview];
                 }
 ];

但是我在这里的答案中看到的是,上面的块不足以进行“异步”回调。相反,我实际上需要在block中使用GCD队列如下面的代码:

- (void)invokeAsync:(id (^)(void))asyncBlock resultBlock:(void (^)(id))resultBlock errorBlock:(void (^)(id))errorBlock {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        id result = nil;
        id error = nil;
        @try {
            result = asyncBlock();
        } @catch (NSException *exception) {
            NSLog(@"caught exception: %@", exception);
            error = exception;
        }
        // tell the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSAutoreleasePool *secondaryPool = [[NSAutoreleasePool alloc] init];
            if (error != nil) {
                errorBlock(error);
            } else {
                resultBlock(result);
            }
            [secondaryPool release];
        });
        [pool release];
    });
}
4

2 回答 2

3

异步回调是您的当前线程继续执行语句,并且您将代码的执行分离到另一个线程中以稍后运行。

有几种技术可以实现这一点。在这个例子中,我以 4 种不同的异步方式使用参数 image(只是一个例子)调用方法 cacheImage:。

// 1. NSThread
[NSThread detachNewThreadSelector:@selector(cacheImage:) toTarget:self withObject:image];

// 2. performSelector...
[self performSelectorInBackground:@selector(cacheImage:) withObject:image];

// 3. NSOperationQueue
NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(cacheImage:) object:image];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:invOperation];

// 4. GCD
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self cacheImage:image];
});

到目前为止,更简单的方法是使用 GCD,因为它已经有一个线程可供您使用,而不必使用其他选项自己创建它。

但是,由于块是作为对象实现的,因此您确实可以在没有 GCD 的情况下使用块,例如:

// block definition
typedef void (^hello_t)();

// method that uses a block as parameter
-(void) runBlock:(hello_t)hello {
    hello();
}

// asynchronous execution of a block
[NSThread detachNewThreadSelector:@selector(runBlock) toTarget:self withObject:^(){
    NSLog(@"hi");
}];

PS:你不需要手动使用 NSAutoreleasePool ,除非你创建了很多对象并且你想立即释放内存。此外,@try @catch 在 Objective-C 中很少使用

于 2013-10-11T16:21:11.913 回答
2

这里没有任何混淆点。GCD 也有一个块执行。GCD API,它支持在系统的 Unix 级别异步执行操作。

块对象是 C 级语法和运行时特性。它们类似于标准 C 函数,但除了可执行代码之外,它们还可能包含与自动(堆栈)或托管(堆)内存的变量绑定。因此,一个块可以维护一组状态(数据),它可以用来在执行时影响行为。

Apple 设计块的明确目标是更容易为 Grand Central Dispatch 线程架构编写程序,尽管它独立于该架构并且可以以与其他语言中的闭包大致相同的方式使用。Apple 在他们自己的 GNU Compiler Collection 分支和 Clang LLVM 编译器前端都实现了块。块的语言运行时库支持也可作为 LLVM 项目的一部分。

因此,给定相同的功能,您可以使用其中任何一种。

于 2013-10-11T05:07:38.273 回答