libdispatch的dispatch_data_apply中偏移量变量的重点是什么?

时间:2018-02-22 01:01:28

标签: macos libdispatch

我无法理解为dispatch_io_read函数调用提供给数据应用程序的偏移量变量。我看到documentation声称偏移量是与数据对象基数的逻辑偏移量。查看dispatch_data_apply函数的source code确认此变量始终从0开始,第一次申请数据块,然后只是范围长度的总和。

我想我当时并不了解这个变量的用途。我最初认为这是整个阅读的偏移量,但事实并非如此。看来你必须跟踪读取的字节数和偏移量,才能在libdispatch中实际正确读取。

// Outside the dispatch_io_read handler...
char * currBufferPosition = destinationBuffer;

// Inside the dispatch_io_read handler...
dispatch_io_read(channel, fileOffset, bytesRequested, queue, ^(bool done, dispatch_data_t data, int error) {
  // Note: Real code would handle error variable.
  dispatch_data_apply(data, ^bool(dispatch_data_t region, size_t offset, const void * buffer, size_t size) {
    memcpy(currBufferPosition, buffer, size);
    currBufferPosition += size;
    return true;
  });
});

我的问题是:这是使用dispatch_data_apply返回的数据的正确方法吗?如果是这样,传递给应用程序处理程序的偏移量变量的目的是什么?这篇文档对我来说似乎并不清楚。

1 个答案:

答案 0 :(得分:0)

dispatch_data_t是一个字节序列。字节可以存储在多个非连续的字节数组中。例如,字节0-6可以存储在一个数组中,然后字节7-12存储在内存中其他位置的单独数组中。

为了提高效率,dispatch_data_apply函数允许您就地迭代这些数组(不复制数据)。在每次调用“applier”时,您会收到指向buffer参数中的一个底层存储阵列的指针。 size参数告诉你这个特定数组中有多少字节,offset参数告诉你这个特定数组的第一个字节是如何(逻辑上)远离整个{{的第一个字节。 1}}。

示例:

dispatch_data_t

输出:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        dispatch_data_t aData = dispatch_data_create("Hello, ", 7, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
        dispatch_data_t bData = dispatch_data_create("world!", 6, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
        dispatch_data_t cData = dispatch_data_create_concat(aData, bData);

        dispatch_data_apply(cData, ^bool(dispatch_data_t  _Nonnull region, size_t offset, const void * _Nonnull buffer, size_t size) {
            printf("applying at offset %lu, buffer %p, size %lu, contents: [%*.*s]\n", (unsigned long)offset, buffer, (unsigned long)size, (int)size, (int)size, buffer);
            return true;
        });
    }
    return 0;
}

好的,这就是applying at offset 0, buffer 0x100407970, size 7, contents: [Hello, ] applying at offset 7, buffer 0x1004087b0, size 6, contents: [world!] 参数的用途。现在,这与offset有什么关系?

好吧,dispatch_io_read两次没有传递相同的字节。一旦它传递了一些字节,就会丢弃它们。下次传递字节时,它们是新读取的新字节。如果你想要旧的字节,你必须自己保持它们。如果您想知道在当前调用回调之前给出了多少旧字节,您必须自己保留该数量。这不是dispatch_io_read参数的用途。

offset调用你时,它可能会传递给你一个dispatch_io_read,它将其字节存储在多个非连续数组中,所以当你在它上面调用dispatch_data_t时,你的应用程序多次调用,具有不同的dispatch_data_apply s和offset s以及buffer s。但是这些调用只会让您访问当前调用回调的新字节,而不是之前调用回调的旧字节。