2

我正在尝试更好地创建更多可重用的代码。目前在我们的应用程序中,我们有一个 DataManager 单例,所有对数据库的调用都会经过。因此,对于昂贵的数据库查找,我想将该调用放在嵌套的 dispatch_async 块中,以免阻塞主线程。所以目前,

在 ViewControllerA 中:

dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue, ^{
  NSArray *array = [DataManager myExpensiveMethodCall];
  dispatch_async(dispatch_get_main_queue(), ^{
    [self setEvents:array];
  });
});

我想知道是否有办法更好地抽象这种类型的“模式”。我在 Apple 的示例代码中看到了它,并且每当我需要执行昂贵的方法然后更新 UI 时,我基本上都会执行这种类型的嵌套 dispatch_async 调用。我只是好奇将这种类型的代码放在需要做这种事情的任何 ViewController 中是否“可以”,或者是否有更好的方法。谢谢。

4

3 回答 3

3

在 .h 文件中,将其放在任何 @interface 之外

typedef void(^MyBlockType)(void);

在你的 .m 文件中,你可以使用这样的东西

+(void)doAsyncWithBlock:(MyBlockType)asyncBlock andSyncBlock:(MyBlockType)syncBlock
{
    dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(aQueue, ^{
        if( asyncBlock != nil )
        {
            asyncBlock();
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            if( syncBlock != nil )
            {
                syncBlock();
            }
        });
    });
}
于 2013-02-12T03:14:07.680 回答
0

是的,可以做到这一点,我看到的主要优势是您可以消除对 GCD 的依赖,并使您的大部分代码与您的主要并发技术无关。

我认为启动一个负责管理异步工作单元的调度和协调它们的回调的新类是合理的,而不是将其添加到视图控制器类中。这样的对象以后可以维护自定义调度队列或NSOperationQueues 或任何未来的技术出现。我正在想象一个带有默认实例的东西,它还提供一个 API 来调度与底层线程技术无关的块。使用 GCD 的一个可能示例如下:

typedef void(^AsynchronousWorkManagerBlock)();

@interface AsynchronousWorkManager : NSObject

+ (AsynchronousWorkManager *)defaultManager;

- (void)executeInBackground:(AsynchronousWorkManagerBlock)backgroundBlock
     withMainThreadCallback:(AsynchronousWorkManagerBlock)callbackBlock;

@end


@implementation AsynchronousWorkManager

+ (AsynchronousWorkManager *)defaultManager
{
    static dispatch_once_t onceToken;
    static AsynchronousWorkManager *DefaultManager = nil;
    dispatch_once(&onceToken, ^{
        DefaultManager = [[self alloc] init];
    });
    return DefaultManager;
}

- (void)executeInBackground:(AsynchronousWorkManagerBlock)backgroundBlock
     withMainThreadCallback:(AsynchronousWorkManagerBlock)callbackBlock
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        backgroundBlock();
        dispatch_async(dispatch_get_main_queue(), callbackBlock);
    });
}

@end

客户端代码可以这样调用它:

[[AsynchronousWorkManager defaultManager] executeInBackground:^{
                                            NSLog(@"This code is happening in the background");
                                        }
                                      withMainThreadCallback:^{
                                            NSLog(@"This code is happening on the main thread");
                                        }];

[[AsynchronousWorkManager defaultManager] executeInBackground:^{
                                            sleep(3);
                                        }
                                      withMainThreadCallback:^{
                                          NSLog(@"Done Sleeping");
                                      }];

稍后,如果您决定改用 usingNSOperationQueue而不是 GCD,则无需更改 API 即可直接更改,如以下示例实现所示:

@interface AsynchronousWorkManager ()

@property (nonatomic, strong) NSOperationQueue *operationQueue;

@end


@implementation AsynchronousWorkManager

+ (AsynchronousWorkManager *)defaultManager
{
    static dispatch_once_t onceToken;
    static AsynchronousWorkManager *DefaultManager = nil;
    dispatch_once(&onceToken, ^{
        DefaultManager = [[self alloc] init];
    });
    return DefaultManager;
}

- (id)init
{
    if (self = [super init]) {
        _operationQueue = [[NSOperationQueue alloc] init];
    }

    return self;
}

- (void)executeInBackground:(AsynchronousWorkManagerBlock)backgroundBlock
     withMainThreadCallback:(AsynchronousWorkManagerBlock)callbackBlock
{
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:backgroundBlock];
    blockOperation.completionBlock = ^{ [[NSOperationQueue mainQueue] addOperationWithBlock:callbackBlock]; };

    [self.operationQueue addOperation:blockOperation];
}

@end

我不完全确定这是多么必要,但由于它可以在没有太多代码的情况下完成,我认为它可能是值得的,而不仅仅是过度工程的练习。如果您的应用程序广泛使用不同的优先级队列或更专业的 GCD 功能,我会谨慎使用此功能,因为可能会在没有真正获得任何底层实现灵活性的情况下引入泄漏抽象。

于 2013-02-12T04:21:13.567 回答
0

我通常定义这两个函数。它们使代码更紧凑,并遵循我在您不想阻塞主线程的地方使用的模式(因此 RUN_ON_BACKGROUND_THREAD 调用是异步的)但是可以阻塞后台线程以更新主线程(因此RUN_ON_UI_THREAD) 调用是同步的。如果调用是从主线程调用的,它还允许直接执行调用,从而避免死锁。

void RUN_ON_UI_THREAD(dispatch_block_t block)
{
    if ([NSThread isMainThread])
        block();
    else
        dispatch_sync(dispatch_get_main_queue(), block);
}

void RUN_ON_BACKGROUND_THREAD(dispatch_block_t block)
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
}
于 2013-02-12T04:54:21.137 回答