【问题标题】:GCD add block into a serial queue after state changed状态改变后 GCD 将块添加到串行队列中
【发布时间】:2015-12-04 09:10:36
【问题描述】:

最近我在使用 GCD 时遇到问题。下面是一些代码sn-p:

static dispatch_queue_t queue() {
    static dispatch_queue_t sl_queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sl_queue = dispatch_queue_create("com.somnus.xxx", NULL);
    });

    return sl_queue;
}

- (void)test
{
        while (self.state != finished)
        {
            //wait for finish
        }

        dispatch_async(queue(), ^{

                self.state = processing;


            void (^onFinish)(void) = 0;
            onFinish = ^(void){
                self.state = finished; 
            };

            [someObj doSomethingWithFinishBlock:onFinish];

        });
}

我想确保每次 test() 方法将块添加到队列中时,状态都是完成的。也就是说,调用test时,检查状态,如果发现状态正在处理,等待状态变为finished,然后执行dispatch_async()。

我该如何实现这个,感谢您的帮助!

编辑:

doSomethingWithFinishBlock是一个异步函数,不知道onFinish Block什么时候入队

【问题讨论】:

  • doSomethingWithFinishBlock是异步函数吗?
  • @Cy-4AH 是的,doSomethingWithFinishBlock 是一个异步函数

标签: ios objective-c objective-c-blocks


【解决方案1】:

这通常通过dispatch_semaphore 完成。大致如下:

@property (nonatomic, readwrite, strong) dispatch_semaphore_t sem;

// ... At some point you must initialize it to 1
// this essentially creates a pool of 1 token to share.
self.sem = dispatch_semaphore_create(1);

- (void)test
{
    // Checkout a token from the pool (there's only one)
    // block until I can get get. You could also timeout, which can be useful.
    dispatch_semphore_wait(self.sem, DISPATCH_TIME_FOREVER);

    // Do a weak-self dance here if you need one. You may not in your example.
    dispatch_async(queue(), ^{
        dispatch_block_t onFinish = ^{
            // Return the token to the pool
            dispatch_semaphore_signal(self.sem)
        };

        [someObj doSomethingWithFinishBlock:onFinish];
   });
}

【讨论】:

    【解决方案2】:

    您应该在 dispatch_queue_create("com.somnus.xxx", NULL); 中使用 DISPATCH_QUEUE_SERIAL

    那么你就不必这样做了

        while (self.state != finished)
        {
            //wait for finish
        }
    

    因为块被排入队列并一个接一个地执行。

    存在块,因此您不必主动等待。那么你就不必拥有状态变量了。

    整个事情就是:

    static dispatch_queue_t queue() {
        static dispatch_queue_t sl_queue;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sl_queue = dispatch_queue_create("com.somnus.xxx", DISPATCH_QUEUE_SERIAL);
        });
    
        return sl_queue;
    }
    
    - (void)test
    {
        dispatch_async(queue(), ^{
            [someObj doSomethingWithFinishBlock:nil];
        });
    }
    

    【讨论】:

    • "你应该在你的 dispatch_queue_create("com.somnus.xxx", NULL); 中使用 DISPATCH_QUEUE_SERIAL;" DISPATCH_QUEUE_SERIAL 定义为 NULL
    • @Alistra,我想确保 onFinish 块在下一个 [someObj doSomethingWithFinishBlock:nil] 块之前排队。
    • @newacct 代码可读性很重要,没有文档就没有人知道 NULL 意味着什么
    • @Alistra:实际上在以前的 SDK 版本中,当只能创建串行队列时,该参数未使用,文档特别告诉您传递 NULL。后来,他们添加了创建并发队列的功能,并添加了DISPATCH_QUEUE_SERIALDISPATCH_QUEUE_CONCURRENT。他们有NULL 的事实并不意味着它写得不好。
    • @Alistra:无论如何,重点是你关于“那你就不必做......”的陈述是不正确或不相关的,因为DISPATCH_QUEUE_SERIALNULL 之间没有区别.
    猜你喜欢
    • 2013-10-11
    • 2022-08-23
    • 1970-01-01
    • 2016-04-05
    • 2012-12-17
    • 2013-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多