ios - 使用串行调度队列调用接受完成 block 作为参数的方法

标签 ios objective-c objective-c-blocks grand-central-dispatch dispatch-async

我有一个方法:

-(void) dataForRequest:(NSMutableURLRequest*)url withCallback:(void (^)(NSData* data))callbackBlock` 

它在后台从 URL 中获取数据,然后用接收到的数据调用 callbackBlock

我在串行队列上调用它,例如:

dispatch_async(my_serial_queue(), ^(void) {
    [dataForRequest:SOME_REQUEST withCallback:^(NSData *data) {
      // do something with data here.
}];

});

我在串行队列上执行此操作的原因是因为我希望请求按发出顺序一次调用一个。

但我面临的问题是,请求是按顺序发出的,但是我传递给方法的 callbackBlock NOT 在 < strong>顺序。

例如,request_1request_2request_3 以正确的顺序提交到串行队列,但是 callBackBlock_1callBackBlock_2callBackBlock_3 的执行顺序不同。

我明白为什么会这样,但我无法找到任何解决方案。 任何帮助将不胜感激。谢谢!

最佳答案

这是一个在 Swift 中实现的解决方案,完全基于 GCD。这种方法是纯异步的,除了最后一条语句 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER) 存在只是为了让主线程保持事件状态,直到所有任务和延续完成。

将此示例移植到 Objective-C 应该不会太困难。关键可能是正确获取 dispatch_groups 的导入引用。

下面的代码创建了十个名为“1”、“2”、.. 和“10”的异步任务。每个任务的持续时间在 0 到 8 秒之间随机。每个任务的继续将打印其名称。

因此,输出应该是这样的,即名称将按照预定的顺序打印 - 无论持续时间如何。 可能是这样的情况,即在仍有任务执行时已打印名称。

import Foundation


let queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL)


func task(duration: Double, completion: ()->()) {
    let t = dispatch_time(DISPATCH_TIME_NOW, (Int64)(duration * Double(NSEC_PER_SEC)))
    dispatch_after(t, dispatch_get_global_queue(0, 0)) {
        completion()
    }
}


func test(params: [String], continuation: ()->()) {
    let g0 = dispatch_group_create()
    dispatch_group_enter(g0)
    var g_prev = g0

    for s in params {
        let g = dispatch_group_create()
        dispatch_group_enter(g)
        let t = Double(arc4random() % 8)
        print("schedule task \"\(s)\" with duration \(t)")
        let gp = g_prev
        task(t) {
            print("finished task \"\(s)\"")
            dispatch_group_notify(gp, queue) { [g]
                print(s)
                dispatch_group_leave(g)
            }
        }
        g_prev = g

    }
    dispatch_group_leave(g0)

    dispatch_group_notify(g_prev, dispatch_get_global_queue(0, 0)) {
        continuation()
    }
}


let sem = dispatch_semaphore_create(0)
test(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]) {
    print("finished")
    dispatch_semaphore_signal(sem)
}

dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)

关于ios - 使用串行调度队列调用接受完成 block 作为参数的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33077913/

相关文章:

ios - Apple 推荐的哪种方法允许我在 Interface Builder 中连接 socket ?

ios - 在 Swift 中的 tableviewcell 之间添加空间

ios - 如何使用Objective-C从纯文本远程文件中读取内容

ios - UITextField 忽略带有临时重音的 shouldChangeCharactersIn

iOS:多语言/多应用,应用商店会被拒绝吗?

ios - 当我转到 Debug模式时,Pods 中的 .a 文件变为红色

objective-c - 在 C 和 Objective C 中,我们是否应该几乎永远不要仅使用 (int) 将 float 或 double 值转换为整数?

objective-c - 声明对 block typedef 的前向引用?

iOS 在 afnetworking 2.0 成功和失败 block 中设置属性时出现问题

iphone - iOS - prepareForSegue 不等待完成 block 完成